Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
82
third_party/FreeRDP/server/Windows/CMakeLists.txt
vendored
Normal file
82
third_party/FreeRDP/server/Windows/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP Windows Server 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 "wfreerdp-server")
|
||||
set(MODULE_PREFIX "FREERDP_SERVER_WINDOWS")
|
||||
|
||||
include(WarnUnmaintained)
|
||||
warn_unmaintained(${MODULE_NAME} "-DWITH_PLATFORM_SERVER=OFF")
|
||||
|
||||
include_directories(.)
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
wf_update.c
|
||||
wf_update.h
|
||||
wf_dxgi.c
|
||||
wf_dxgi.h
|
||||
wf_input.c
|
||||
wf_input.h
|
||||
wf_interface.c
|
||||
wf_interface.h
|
||||
wf_mirage.c
|
||||
wf_mirage.h
|
||||
wf_peer.c
|
||||
wf_peer.h
|
||||
wf_settings.c
|
||||
wf_settings.h
|
||||
wf_info.c
|
||||
wf_info.h
|
||||
)
|
||||
|
||||
if(CHANNEL_RDPSND AND NOT WITH_RDPSND_DSOUND)
|
||||
set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} wf_rdpsnd.c wf_rdpsnd.h wf_wasapi.c wf_wasapi.h)
|
||||
endif()
|
||||
|
||||
if(CHANNEL_RDPSND AND WITH_RDPSND_DSOUND)
|
||||
set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} wf_rdpsnd.c wf_rdpsnd.h wf_directsound.c wf_directsound.h)
|
||||
endif()
|
||||
|
||||
if(WITH_SERVER_INTERFACE)
|
||||
addtargetwithresourcefile(${MODULE_NAME} FALSE "${FREERDP_VERSION}" ${MODULE_PREFIX}_SRCS)
|
||||
target_include_directories(${MODULE_NAME} INTERFACE $<INSTALL_INTERFACE:include>)
|
||||
else()
|
||||
list(APPEND ${MODULE_PREFIX}_SRCS cli/wfreerdp.c cli/wfreerdp.h)
|
||||
addtargetwithresourcefile(${MODULE_NAME} TRUE "${FREERDP_VERSION}" ${MODULE_PREFIX}_SRCS)
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_WINDOWS_VERSION STREQUAL "WINXP")
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} d3d11 dxgi)
|
||||
endif()
|
||||
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} dsound)
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-server freerdp)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
|
||||
if(WITH_SERVER_INTERFACE)
|
||||
install(TARGETS ${MODULE_NAME} COMPONENT libraries ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
else()
|
||||
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT server)
|
||||
endif()
|
||||
|
||||
if(WITH_SERVER_INTERFACE)
|
||||
add_subdirectory(cli)
|
||||
endif()
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Server/Windows")
|
||||
3
third_party/FreeRDP/server/Windows/ModuleOptions.cmake
vendored
Normal file
3
third_party/FreeRDP/server/Windows/ModuleOptions.cmake
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
set(FREERDP_SERVER_NAME "wfreerdp-server")
|
||||
set(FREERDP_SERVER_PLATFORM "Windows")
|
||||
set(FREERDP_SERVER_VENDOR "FreeRDP")
|
||||
34
third_party/FreeRDP/server/Windows/cli/CMakeLists.txt
vendored
Normal file
34
third_party/FreeRDP/server/Windows/cli/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP Windows Server (CLI) 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 "wfreerdp-server-cli")
|
||||
set(OUTPUT_NAME "wfreerdp-server")
|
||||
set(MODULE_PREFIX "FREERDP_SERVER_WINDOWS_CLI")
|
||||
|
||||
include_directories(..)
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS wfreerdp.c wfreerdp.h)
|
||||
|
||||
addtargetwithresourcefile(${MODULE_NAME} TRUE "${FREERDP_VERSION}" ${MODULE_PREFIX}_SRCS)
|
||||
|
||||
set(${MODULE_PREFIX}_LIBS wfreerdp-server)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
|
||||
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT server)
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Server/Windows")
|
||||
171
third_party/FreeRDP/server/Windows/cli/wfreerdp.c
vendored
Normal file
171
third_party/FreeRDP/server/Windows/cli/wfreerdp.c
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Windows Server
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <winpr/tchar.h>
|
||||
#include <winpr/windows.h>
|
||||
|
||||
#include "wf_interface.h"
|
||||
|
||||
#include "wfreerdp.h"
|
||||
|
||||
#include <freerdp/server/server-common.h>
|
||||
#include <freerdp/log.h>
|
||||
#define TAG SERVER_TAG("windows")
|
||||
|
||||
int IDcount = 0;
|
||||
|
||||
BOOL CALLBACK moncb(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
|
||||
{
|
||||
WLog_DBG(TAG, "%d\t(%ld, %ld), (%ld, %ld)", IDcount, lprcMonitor->left, lprcMonitor->top,
|
||||
lprcMonitor->right, lprcMonitor->bottom);
|
||||
IDcount++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
freerdp_server_warn_unmaintained(argc, argv);
|
||||
|
||||
BOOL screen_selected = FALSE;
|
||||
int index = 1;
|
||||
wfServer* server;
|
||||
server = wfreerdp_server_new();
|
||||
set_screen_id(0);
|
||||
// handle args
|
||||
errno = 0;
|
||||
|
||||
while (index < argc)
|
||||
{
|
||||
// first the args that will cause the program to terminate
|
||||
if (strcmp("--list-screens", argv[index]) == 0)
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
int bpp;
|
||||
WLog_INFO(TAG, "Detecting screens...");
|
||||
WLog_INFO(TAG, "ID\tResolution\t\tName (Interface)");
|
||||
|
||||
for (int i = 0;; i++)
|
||||
{
|
||||
_TCHAR name[128] = WINPR_C_ARRAY_INIT;
|
||||
if (get_screen_info(i, name, ARRAYSIZE(name), &width, &height, &bpp) != 0)
|
||||
{
|
||||
if ((width * height * bpp) == 0)
|
||||
continue;
|
||||
|
||||
WLog_INFO(TAG, "%d\t%dx%dx%d\t", i, width, height, bpp);
|
||||
WLog_INFO(TAG, "%s", name);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int vscreen_w;
|
||||
int vscreen_h;
|
||||
vscreen_w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
|
||||
vscreen_h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
|
||||
WLog_INFO(TAG, "");
|
||||
EnumDisplayMonitors(nullptr, nullptr, moncb, 0);
|
||||
IDcount = 0;
|
||||
WLog_INFO(TAG, "Virtual Screen = %dx%d", vscreen_w, vscreen_h);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp("--screen", argv[index]) == 0)
|
||||
{
|
||||
UINT32 val;
|
||||
screen_selected = TRUE;
|
||||
index++;
|
||||
|
||||
if (index == argc)
|
||||
{
|
||||
WLog_INFO(TAG, "missing screen id parameter");
|
||||
return 0;
|
||||
}
|
||||
|
||||
val = strtoul(argv[index], nullptr, 0);
|
||||
|
||||
if ((errno != 0) || (val > UINT32_MAX))
|
||||
return -1;
|
||||
|
||||
set_screen_id(val);
|
||||
index++;
|
||||
}
|
||||
|
||||
if (index == argc - 1)
|
||||
{
|
||||
UINT32 val = strtoul(argv[index], nullptr, 0);
|
||||
|
||||
if ((errno != 0) || (val > UINT32_MAX))
|
||||
return -1;
|
||||
|
||||
server->port = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (screen_selected == FALSE)
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
int bpp;
|
||||
WLog_INFO(TAG, "screen id not provided. attempting to detect...");
|
||||
WLog_INFO(TAG, "Detecting screens...");
|
||||
WLog_INFO(TAG, "ID\tResolution\t\tName (Interface)");
|
||||
|
||||
for (int i = 0;; i++)
|
||||
{
|
||||
_TCHAR name[128] = WINPR_C_ARRAY_INIT;
|
||||
if (get_screen_info(i, name, ARRAYSIZE(name), &width, &height, &bpp) != 0)
|
||||
{
|
||||
if ((width * height * bpp) == 0)
|
||||
continue;
|
||||
|
||||
WLog_INFO(TAG, "%d\t%dx%dx%d\t", i, width, height, bpp);
|
||||
WLog_INFO(TAG, "%s", name);
|
||||
set_screen_id(i);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WLog_INFO(TAG, "Starting server");
|
||||
wfreerdp_server_start(server);
|
||||
(void)WaitForSingleObject(server->thread, INFINITE);
|
||||
WLog_INFO(TAG, "Stopping server");
|
||||
wfreerdp_server_stop(server);
|
||||
wfreerdp_server_free(server);
|
||||
return 0;
|
||||
}
|
||||
25
third_party/FreeRDP/server/Windows/cli/wfreerdp.h
vendored
Normal file
25
third_party/FreeRDP/server/Windows/cli/wfreerdp.h
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Windows Server
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_WIN_FREERDP_H
|
||||
#define FREERDP_SERVER_WIN_FREERDP_H
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
|
||||
#endif /* FREERDP_SERVER_WIN_FREERDP_H */
|
||||
219
third_party/FreeRDP/server/Windows/wf_directsound.c
vendored
Normal file
219
third_party/FreeRDP/server/Windows/wf_directsound.c
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
#include "wf_directsound.h"
|
||||
#include "wf_interface.h"
|
||||
#include "wf_info.h"
|
||||
#include "wf_rdpsnd.h"
|
||||
|
||||
#include <winpr/windows.h>
|
||||
|
||||
#define INITGUID
|
||||
#include <initguid.h>
|
||||
#include <objbase.h>
|
||||
|
||||
#define CINTERFACE 1
|
||||
#include <mmsystem.h>
|
||||
#include <dsound.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG SERVER_TAG("windows")
|
||||
|
||||
IDirectSoundCapture8* cap;
|
||||
IDirectSoundCaptureBuffer8* capBuf;
|
||||
DSCBUFFERDESC dscbd;
|
||||
DWORD lastPos;
|
||||
wfPeerContext* latestPeer;
|
||||
|
||||
int wf_rdpsnd_set_latest_peer(wfPeerContext* peer)
|
||||
{
|
||||
latestPeer = peer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wf_directsound_activate(RdpsndServerContext* context)
|
||||
{
|
||||
HRESULT hr;
|
||||
wfInfo* wfi;
|
||||
HANDLE hThread;
|
||||
|
||||
LPDIRECTSOUNDCAPTUREBUFFER pDSCB;
|
||||
|
||||
wfi = wf_info_get_instance();
|
||||
if (!wfi)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to wfi instance");
|
||||
return 1;
|
||||
}
|
||||
WLog_DBG(TAG, "RDPSND (direct sound) Activated");
|
||||
hr = DirectSoundCaptureCreate8(nullptr, &cap, nullptr);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to create sound capture device");
|
||||
return 1;
|
||||
}
|
||||
|
||||
WLog_INFO(TAG, "Created sound capture device");
|
||||
dscbd.dwSize = sizeof(DSCBUFFERDESC);
|
||||
dscbd.dwFlags = 0;
|
||||
dscbd.dwBufferBytes = wfi->agreed_format->nAvgBytesPerSec;
|
||||
dscbd.dwReserved = 0;
|
||||
dscbd.lpwfxFormat = wfi->agreed_format;
|
||||
dscbd.dwFXCount = 0;
|
||||
dscbd.lpDSCFXDesc = nullptr;
|
||||
|
||||
hr = cap->lpVtbl->CreateCaptureBuffer(cap, &dscbd, &pDSCB, nullptr);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to create capture buffer");
|
||||
}
|
||||
|
||||
WLog_INFO(TAG, "Created capture buffer");
|
||||
hr = pDSCB->lpVtbl->QueryInterface(pDSCB, &IID_IDirectSoundCaptureBuffer8, (LPVOID*)&capBuf);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to QI capture buffer");
|
||||
}
|
||||
WLog_INFO(TAG, "Created IDirectSoundCaptureBuffer8");
|
||||
pDSCB->lpVtbl->Release(pDSCB);
|
||||
lastPos = 0;
|
||||
|
||||
if (!(hThread = CreateThread(nullptr, 0, wf_rdpsnd_directsound_thread, latestPeer, 0, nullptr)))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to create direct sound thread");
|
||||
return 1;
|
||||
}
|
||||
(void)CloseHandle(hThread);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DWORD WINAPI wf_rdpsnd_directsound_thread(LPVOID lpParam)
|
||||
{
|
||||
HRESULT hr;
|
||||
DWORD beg = 0;
|
||||
DWORD end = 0;
|
||||
DWORD diff, rate;
|
||||
wfPeerContext* context;
|
||||
wfInfo* wfi;
|
||||
|
||||
VOID* pbCaptureData = nullptr;
|
||||
DWORD dwCaptureLength = 0;
|
||||
VOID* pbCaptureData2 = nullptr;
|
||||
DWORD dwCaptureLength2 = 0;
|
||||
VOID* pbPlayData = nullptr;
|
||||
DWORD dwReadPos = 0;
|
||||
LONG lLockSize = 0;
|
||||
|
||||
wfi = wf_info_get_instance();
|
||||
if (!wfi)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed get instance");
|
||||
return 1;
|
||||
}
|
||||
|
||||
context = (wfPeerContext*)lpParam;
|
||||
rate = 1000 / 24;
|
||||
WLog_INFO(TAG, "Trying to start capture");
|
||||
hr = capBuf->lpVtbl->Start(capBuf, DSCBSTART_LOOPING);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to start capture");
|
||||
}
|
||||
WLog_INFO(TAG, "Capture started");
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
||||
end = GetTickCount();
|
||||
diff = end - beg;
|
||||
|
||||
if (diff < rate)
|
||||
{
|
||||
Sleep(rate - diff);
|
||||
}
|
||||
|
||||
beg = GetTickCount();
|
||||
|
||||
if (wf_rdpsnd_lock() > 0)
|
||||
{
|
||||
// check for main exit condition
|
||||
if (wfi->snd_stop == TRUE)
|
||||
{
|
||||
wf_rdpsnd_unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
hr = capBuf->lpVtbl->GetCurrentPosition(capBuf, nullptr, &dwReadPos);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get read pos");
|
||||
wf_rdpsnd_unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
lLockSize = dwReadPos - lastPos; // dscbd.dwBufferBytes;
|
||||
if (lLockSize < 0)
|
||||
lLockSize += dscbd.dwBufferBytes;
|
||||
|
||||
// WLog_DBG(TAG, "Last, read, lock = [%"PRIu32", %"PRIu32", %"PRId32"]\n", lastPos,
|
||||
// dwReadPos, lLockSize);
|
||||
|
||||
if (lLockSize == 0)
|
||||
{
|
||||
wf_rdpsnd_unlock();
|
||||
continue;
|
||||
}
|
||||
|
||||
hr = capBuf->lpVtbl->Lock(capBuf, lastPos, lLockSize, &pbCaptureData, &dwCaptureLength,
|
||||
&pbCaptureData2, &dwCaptureLength2, 0L);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to lock sound capture buffer");
|
||||
wf_rdpsnd_unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
// fwrite(pbCaptureData, 1, dwCaptureLength, pFile);
|
||||
// fwrite(pbCaptureData2, 1, dwCaptureLength2, pFile);
|
||||
|
||||
// FIXME: frames = bytes/(bytespersample * channels)
|
||||
|
||||
context->rdpsnd->SendSamples(context->rdpsnd, pbCaptureData, dwCaptureLength / 4,
|
||||
(UINT16)(beg & 0xffff));
|
||||
context->rdpsnd->SendSamples(context->rdpsnd, pbCaptureData2, dwCaptureLength2 / 4,
|
||||
(UINT16)(beg & 0xffff));
|
||||
|
||||
hr = capBuf->lpVtbl->Unlock(capBuf, pbCaptureData, dwCaptureLength, pbCaptureData2,
|
||||
dwCaptureLength2);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to unlock sound capture buffer");
|
||||
wf_rdpsnd_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO keep track of location in buffer
|
||||
lastPos += dwCaptureLength;
|
||||
lastPos %= dscbd.dwBufferBytes;
|
||||
lastPos += dwCaptureLength2;
|
||||
lastPos %= dscbd.dwBufferBytes;
|
||||
|
||||
wf_rdpsnd_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
WLog_INFO(TAG, "Trying to stop sound capture");
|
||||
hr = capBuf->lpVtbl->Stop(capBuf);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to stop capture");
|
||||
}
|
||||
|
||||
WLog_INFO(TAG, "Capture stopped");
|
||||
capBuf->lpVtbl->Release(capBuf);
|
||||
cap->lpVtbl->Release(cap);
|
||||
|
||||
lastPos = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
13
third_party/FreeRDP/server/Windows/wf_directsound.h
vendored
Normal file
13
third_party/FreeRDP/server/Windows/wf_directsound.h
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef FREERDP_SERVER_WIN_DSOUND_H
|
||||
#define FREERDP_SERVER_WIN_DSOUND_H
|
||||
|
||||
#include <freerdp/server/rdpsnd.h>
|
||||
#include "wf_interface.h"
|
||||
|
||||
WINPR_ATTR_NODISCARD int wf_rdpsnd_set_latest_peer(wfPeerContext* peer);
|
||||
|
||||
WINPR_ATTR_NODISCARD int wf_directsound_activate(RdpsndServerContext* context);
|
||||
|
||||
WINPR_ATTR_NODISCARD DWORD WINAPI wf_rdpsnd_directsound_thread(LPVOID lpParam);
|
||||
|
||||
#endif /* FREERDP_SERVER_WIN_DSOUND_H */
|
||||
486
third_party/FreeRDP/server/Windows/wf_dxgi.c
vendored
Normal file
486
third_party/FreeRDP/server/Windows/wf_dxgi.c
vendored
Normal file
@@ -0,0 +1,486 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Windows Server
|
||||
*
|
||||
* Copyright 2012 Corey Clayton <can.of.tuna@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 <freerdp/config.h>
|
||||
|
||||
#include "wf_interface.h"
|
||||
|
||||
#ifdef WITH_DXGI_1_2
|
||||
|
||||
#define CINTERFACE
|
||||
|
||||
#include <D3D11.h>
|
||||
#include <dxgi1_2.h>
|
||||
|
||||
#include <tchar.h>
|
||||
#include "wf_dxgi.h"
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG SERVER_TAG("windows")
|
||||
|
||||
/* Driver types supported */
|
||||
D3D_DRIVER_TYPE DriverTypes[] = {
|
||||
D3D_DRIVER_TYPE_HARDWARE,
|
||||
D3D_DRIVER_TYPE_WARP,
|
||||
D3D_DRIVER_TYPE_REFERENCE,
|
||||
};
|
||||
UINT NumDriverTypes = ARRAYSIZE(DriverTypes);
|
||||
|
||||
/* Feature levels supported */
|
||||
D3D_FEATURE_LEVEL FeatureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1,
|
||||
D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_1 };
|
||||
|
||||
UINT NumFeatureLevels = ARRAYSIZE(FeatureLevels);
|
||||
|
||||
D3D_FEATURE_LEVEL FeatureLevel;
|
||||
|
||||
ID3D11Device* gDevice = nullptr;
|
||||
ID3D11DeviceContext* gContext = nullptr;
|
||||
IDXGIOutputDuplication* gOutputDuplication = nullptr;
|
||||
ID3D11Texture2D* gAcquiredDesktopImage = nullptr;
|
||||
|
||||
IDXGISurface* surf;
|
||||
ID3D11Texture2D* sStage;
|
||||
|
||||
DXGI_OUTDUPL_FRAME_INFO FrameInfo;
|
||||
|
||||
int wf_dxgi_init(wfInfo* wfi)
|
||||
{
|
||||
gAcquiredDesktopImage = nullptr;
|
||||
|
||||
if (wf_dxgi_createDevice(wfi) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (wf_dxgi_getDuplication(wfi) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wf_dxgi_createDevice(wfInfo* wfi)
|
||||
{
|
||||
HRESULT status;
|
||||
UINT DriverTypeIndex;
|
||||
|
||||
for (DriverTypeIndex = 0; DriverTypeIndex < NumDriverTypes; ++DriverTypeIndex)
|
||||
{
|
||||
status = D3D11CreateDevice(nullptr, DriverTypes[DriverTypeIndex], nullptr, 0, FeatureLevels,
|
||||
NumFeatureLevels, D3D11_SDK_VERSION, &gDevice, &FeatureLevel,
|
||||
&gContext);
|
||||
if (SUCCEEDED(status))
|
||||
break;
|
||||
|
||||
WLog_INFO(TAG, "D3D11CreateDevice returned [%ld] for Driver Type %d", status,
|
||||
DriverTypes[DriverTypeIndex]);
|
||||
}
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to create device in InitializeDx");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wf_dxgi_getDuplication(wfInfo* wfi)
|
||||
{
|
||||
HRESULT status;
|
||||
UINT dTop, i = 0;
|
||||
DXGI_OUTPUT_DESC desc = WINPR_C_ARRAY_INIT;
|
||||
IDXGIOutput* pOutput;
|
||||
IDXGIDevice* DxgiDevice = nullptr;
|
||||
IDXGIAdapter* DxgiAdapter = nullptr;
|
||||
IDXGIOutput* DxgiOutput = nullptr;
|
||||
IDXGIOutput1* DxgiOutput1 = nullptr;
|
||||
|
||||
status = gDevice->lpVtbl->QueryInterface(gDevice, &IID_IDXGIDevice, (void**)&DxgiDevice);
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get QI for DXGI Device");
|
||||
return 1;
|
||||
}
|
||||
|
||||
status = DxgiDevice->lpVtbl->GetParent(DxgiDevice, &IID_IDXGIAdapter, (void**)&DxgiAdapter);
|
||||
DxgiDevice->lpVtbl->Release(DxgiDevice);
|
||||
DxgiDevice = nullptr;
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get parent DXGI Adapter");
|
||||
return 1;
|
||||
}
|
||||
|
||||
pOutput = nullptr;
|
||||
|
||||
while (DxgiAdapter->lpVtbl->EnumOutputs(DxgiAdapter, i, &pOutput) != DXGI_ERROR_NOT_FOUND)
|
||||
{
|
||||
DXGI_OUTPUT_DESC* pDesc = &desc;
|
||||
|
||||
status = pOutput->lpVtbl->GetDesc(pOutput, pDesc);
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get description");
|
||||
return 1;
|
||||
}
|
||||
|
||||
WLog_INFO(TAG, "Output %u: [%s] [%d]", i, pDesc->DeviceName, pDesc->AttachedToDesktop);
|
||||
|
||||
if (pDesc->AttachedToDesktop)
|
||||
dTop = i;
|
||||
|
||||
pOutput->lpVtbl->Release(pOutput);
|
||||
++i;
|
||||
}
|
||||
|
||||
dTop = wfi->screenID;
|
||||
|
||||
status = DxgiAdapter->lpVtbl->EnumOutputs(DxgiAdapter, dTop, &DxgiOutput);
|
||||
DxgiAdapter->lpVtbl->Release(DxgiAdapter);
|
||||
DxgiAdapter = nullptr;
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get output");
|
||||
return 1;
|
||||
}
|
||||
|
||||
status =
|
||||
DxgiOutput->lpVtbl->QueryInterface(DxgiOutput, &IID_IDXGIOutput1, (void**)&DxgiOutput1);
|
||||
DxgiOutput->lpVtbl->Release(DxgiOutput);
|
||||
DxgiOutput = nullptr;
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get IDXGIOutput1");
|
||||
return 1;
|
||||
}
|
||||
|
||||
status =
|
||||
DxgiOutput1->lpVtbl->DuplicateOutput(DxgiOutput1, (IUnknown*)gDevice, &gOutputDuplication);
|
||||
DxgiOutput1->lpVtbl->Release(DxgiOutput1);
|
||||
DxgiOutput1 = nullptr;
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
if (status == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
|
||||
{
|
||||
WLog_ERR(
|
||||
TAG,
|
||||
"There is already the maximum number of applications using the Desktop Duplication "
|
||||
"API running, please close one of those applications and then try again.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
WLog_ERR(TAG, "Failed to get duplicate output. Status = %ld", status);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wf_dxgi_cleanup(wfInfo* wfi)
|
||||
{
|
||||
if (wfi->framesWaiting > 0)
|
||||
{
|
||||
wf_dxgi_releasePixelData(wfi);
|
||||
}
|
||||
|
||||
if (gAcquiredDesktopImage)
|
||||
{
|
||||
gAcquiredDesktopImage->lpVtbl->Release(gAcquiredDesktopImage);
|
||||
gAcquiredDesktopImage = nullptr;
|
||||
}
|
||||
|
||||
if (gOutputDuplication)
|
||||
{
|
||||
gOutputDuplication->lpVtbl->Release(gOutputDuplication);
|
||||
gOutputDuplication = nullptr;
|
||||
}
|
||||
|
||||
if (gContext)
|
||||
{
|
||||
gContext->lpVtbl->Release(gContext);
|
||||
gContext = nullptr;
|
||||
}
|
||||
|
||||
if (gDevice)
|
||||
{
|
||||
gDevice->lpVtbl->Release(gDevice);
|
||||
gDevice = nullptr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wf_dxgi_nextFrame(wfInfo* wfi, UINT timeout)
|
||||
{
|
||||
HRESULT status = 0;
|
||||
UINT i = 0;
|
||||
UINT DataBufferSize = 0;
|
||||
BYTE* DataBuffer = nullptr;
|
||||
IDXGIResource* DesktopResource = nullptr;
|
||||
|
||||
if (wfi->framesWaiting > 0)
|
||||
{
|
||||
wf_dxgi_releasePixelData(wfi);
|
||||
}
|
||||
|
||||
if (gAcquiredDesktopImage)
|
||||
{
|
||||
gAcquiredDesktopImage->lpVtbl->Release(gAcquiredDesktopImage);
|
||||
gAcquiredDesktopImage = nullptr;
|
||||
}
|
||||
|
||||
status = gOutputDuplication->lpVtbl->AcquireNextFrame(gOutputDuplication, timeout, &FrameInfo,
|
||||
&DesktopResource);
|
||||
|
||||
if (status == DXGI_ERROR_WAIT_TIMEOUT)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
if (status == DXGI_ERROR_ACCESS_LOST)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to acquire next frame with status=%ld", status);
|
||||
WLog_ERR(TAG, "Trying to reinitialize due to ACCESS LOST...");
|
||||
|
||||
if (gAcquiredDesktopImage)
|
||||
{
|
||||
gAcquiredDesktopImage->lpVtbl->Release(gAcquiredDesktopImage);
|
||||
gAcquiredDesktopImage = nullptr;
|
||||
}
|
||||
|
||||
if (gOutputDuplication)
|
||||
{
|
||||
gOutputDuplication->lpVtbl->Release(gOutputDuplication);
|
||||
gOutputDuplication = nullptr;
|
||||
}
|
||||
|
||||
wf_dxgi_getDuplication(wfi);
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to acquire next frame with status=%ld", status);
|
||||
status = gOutputDuplication->lpVtbl->ReleaseFrame(gOutputDuplication);
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to release frame with status=%ld", status);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
status = DesktopResource->lpVtbl->QueryInterface(DesktopResource, &IID_ID3D11Texture2D,
|
||||
(void**)&gAcquiredDesktopImage);
|
||||
DesktopResource->lpVtbl->Release(DesktopResource);
|
||||
DesktopResource = nullptr;
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
wfi->framesWaiting = FrameInfo.AccumulatedFrames;
|
||||
|
||||
if (FrameInfo.AccumulatedFrames == 0)
|
||||
{
|
||||
status = gOutputDuplication->lpVtbl->ReleaseFrame(gOutputDuplication);
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to release frame with status=%ld", status);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wf_dxgi_getPixelData(wfInfo* wfi, BYTE** data, int* pitch, RECT* invalid)
|
||||
{
|
||||
HRESULT status;
|
||||
D3D11_BOX Box;
|
||||
DXGI_MAPPED_RECT mappedRect;
|
||||
D3D11_TEXTURE2D_DESC tDesc;
|
||||
|
||||
tDesc.Width = (invalid->right - invalid->left);
|
||||
tDesc.Height = (invalid->bottom - invalid->top);
|
||||
tDesc.MipLevels = 1;
|
||||
tDesc.ArraySize = 1;
|
||||
tDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
tDesc.SampleDesc.Count = 1;
|
||||
tDesc.SampleDesc.Quality = 0;
|
||||
tDesc.Usage = D3D11_USAGE_STAGING;
|
||||
tDesc.BindFlags = 0;
|
||||
tDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
tDesc.MiscFlags = 0;
|
||||
|
||||
Box.top = invalid->top;
|
||||
Box.left = invalid->left;
|
||||
Box.right = invalid->right;
|
||||
Box.bottom = invalid->bottom;
|
||||
Box.front = 0;
|
||||
Box.back = 1;
|
||||
|
||||
status = gDevice->lpVtbl->CreateTexture2D(gDevice, &tDesc, nullptr, &sStage);
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to create staging surface");
|
||||
exit(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
gContext->lpVtbl->CopySubresourceRegion(gContext, (ID3D11Resource*)sStage, 0, 0, 0, 0,
|
||||
(ID3D11Resource*)gAcquiredDesktopImage, 0, &Box);
|
||||
|
||||
status = sStage->lpVtbl->QueryInterface(sStage, &IID_IDXGISurface, (void**)&surf);
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to QI staging surface");
|
||||
exit(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
surf->lpVtbl->Map(surf, &mappedRect, DXGI_MAP_READ);
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to map staging surface");
|
||||
exit(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
*data = mappedRect.pBits;
|
||||
*pitch = mappedRect.Pitch;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wf_dxgi_releasePixelData(wfInfo* wfi)
|
||||
{
|
||||
HRESULT status;
|
||||
|
||||
surf->lpVtbl->Unmap(surf);
|
||||
surf->lpVtbl->Release(surf);
|
||||
surf = nullptr;
|
||||
sStage->lpVtbl->Release(sStage);
|
||||
sStage = nullptr;
|
||||
|
||||
status = gOutputDuplication->lpVtbl->ReleaseFrame(gOutputDuplication);
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to release frame");
|
||||
return 1;
|
||||
}
|
||||
|
||||
wfi->framesWaiting = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wf_dxgi_getInvalidRegion(RECT* invalid)
|
||||
{
|
||||
HRESULT status;
|
||||
UINT dirty;
|
||||
UINT BufSize;
|
||||
RECT* pRect;
|
||||
BYTE* DirtyRects;
|
||||
UINT DataBufferSize = 0;
|
||||
BYTE* DataBuffer = nullptr;
|
||||
|
||||
if (FrameInfo.AccumulatedFrames == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (FrameInfo.TotalMetadataBufferSize)
|
||||
{
|
||||
|
||||
if (FrameInfo.TotalMetadataBufferSize > DataBufferSize)
|
||||
{
|
||||
if (DataBuffer)
|
||||
{
|
||||
free(DataBuffer);
|
||||
DataBuffer = nullptr;
|
||||
}
|
||||
|
||||
DataBuffer = (BYTE*)malloc(FrameInfo.TotalMetadataBufferSize);
|
||||
|
||||
if (!DataBuffer)
|
||||
{
|
||||
DataBufferSize = 0;
|
||||
WLog_ERR(TAG, "Failed to allocate memory for metadata");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
DataBufferSize = FrameInfo.TotalMetadataBufferSize;
|
||||
}
|
||||
|
||||
BufSize = FrameInfo.TotalMetadataBufferSize;
|
||||
|
||||
status = gOutputDuplication->lpVtbl->GetFrameMoveRects(
|
||||
gOutputDuplication, BufSize, (DXGI_OUTDUPL_MOVE_RECT*)DataBuffer, &BufSize);
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get frame move rects");
|
||||
return 1;
|
||||
}
|
||||
|
||||
DirtyRects = DataBuffer + BufSize;
|
||||
BufSize = FrameInfo.TotalMetadataBufferSize - BufSize;
|
||||
|
||||
status = gOutputDuplication->lpVtbl->GetFrameDirtyRects(gOutputDuplication, BufSize,
|
||||
(RECT*)DirtyRects, &BufSize);
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get frame dirty rects");
|
||||
return 1;
|
||||
}
|
||||
dirty = BufSize / sizeof(RECT);
|
||||
|
||||
pRect = (RECT*)DirtyRects;
|
||||
|
||||
for (UINT i = 0; i < dirty; ++i)
|
||||
{
|
||||
UnionRect(invalid, invalid, pRect);
|
||||
++pRect;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
42
third_party/FreeRDP/server/Windows/wf_dxgi.h
vendored
Normal file
42
third_party/FreeRDP/server/Windows/wf_dxgi.h
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Windows Server
|
||||
*
|
||||
* Copyright 2012 Corey Clayton <can.of.tuna@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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_WIN_DXGI_H
|
||||
#define FREERDP_SERVER_WIN_DXGI_H
|
||||
|
||||
#include "wf_interface.h"
|
||||
|
||||
WINPR_ATTR_NODISCARD int wf_dxgi_init(wfInfo* context);
|
||||
|
||||
WINPR_ATTR_NODISCARD int wf_dxgi_createDevice(wfInfo* context);
|
||||
|
||||
WINPR_ATTR_NODISCARD int wf_dxgi_getDuplication(wfInfo* context);
|
||||
|
||||
WINPR_ATTR_NODISCARD int wf_dxgi_cleanup(wfInfo* context);
|
||||
|
||||
WINPR_ATTR_NODISCARD int wf_dxgi_nextFrame(wfInfo* context, UINT timeout);
|
||||
|
||||
WINPR_ATTR_NODISCARD int wf_dxgi_getPixelData(wfInfo* context, BYTE** data, int* pitch,
|
||||
RECT* invalid);
|
||||
|
||||
WINPR_ATTR_NODISCARD int wf_dxgi_releasePixelData(wfInfo* context);
|
||||
|
||||
WINPR_ATTR_NODISCARD int wf_dxgi_getInvalidRegion(RECT* invalid);
|
||||
|
||||
#endif /* FREERDP_SERVER_WIN_DXGI_H */
|
||||
403
third_party/FreeRDP/server/Windows/wf_info.c
vendored
Normal file
403
third_party/FreeRDP/server/Windows/wf_info.c
vendored
Normal file
@@ -0,0 +1,403 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Client
|
||||
* FreeRDP Windows Server
|
||||
*
|
||||
* Copyright 2012 Corey Clayton <can.of.tuna@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 <freerdp/config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <freerdp/build-config.h>
|
||||
|
||||
#include <winpr/tchar.h>
|
||||
#include <winpr/windows.h>
|
||||
|
||||
#include "wf_info.h"
|
||||
#include "wf_update.h"
|
||||
#include "wf_mirage.h"
|
||||
#include "wf_dxgi.h"
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG SERVER_TAG("windows")
|
||||
|
||||
#define SERVER_KEY "Software\\" FREERDP_VENDOR_STRING "\\" FREERDP_PRODUCT_STRING "\\Server"
|
||||
|
||||
static wfInfo* wfInfoInstance = nullptr;
|
||||
static int _IDcount = 0;
|
||||
|
||||
BOOL wf_info_lock(wfInfo* wfi)
|
||||
{
|
||||
DWORD dRes;
|
||||
dRes = WaitForSingleObject(wfi->mutex, INFINITE);
|
||||
|
||||
switch (dRes)
|
||||
{
|
||||
case WAIT_ABANDONED:
|
||||
case WAIT_OBJECT_0:
|
||||
return TRUE;
|
||||
|
||||
case WAIT_TIMEOUT:
|
||||
return FALSE;
|
||||
|
||||
case WAIT_FAILED:
|
||||
WLog_ERR(TAG, "wf_info_lock failed with 0x%08lX", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL wf_info_try_lock(wfInfo* wfi, DWORD dwMilliseconds)
|
||||
{
|
||||
DWORD dRes;
|
||||
dRes = WaitForSingleObject(wfi->mutex, dwMilliseconds);
|
||||
|
||||
switch (dRes)
|
||||
{
|
||||
case WAIT_ABANDONED:
|
||||
case WAIT_OBJECT_0:
|
||||
return TRUE;
|
||||
|
||||
case WAIT_TIMEOUT:
|
||||
return FALSE;
|
||||
|
||||
case WAIT_FAILED:
|
||||
WLog_ERR(TAG, "wf_info_try_lock failed with 0x%08lX", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL wf_info_unlock(wfInfo* wfi)
|
||||
{
|
||||
if (!ReleaseMutex(wfi->mutex))
|
||||
{
|
||||
WLog_ERR(TAG, "wf_info_unlock failed with 0x%08lX", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
wfInfo* wf_info_init()
|
||||
{
|
||||
wfInfo* wfi;
|
||||
wfi = (wfInfo*)calloc(1, sizeof(wfInfo));
|
||||
|
||||
if (wfi != nullptr)
|
||||
{
|
||||
HKEY hKey;
|
||||
LONG status;
|
||||
DWORD dwType;
|
||||
DWORD dwSize;
|
||||
DWORD dwValue;
|
||||
wfi->mutex = CreateMutex(nullptr, FALSE, nullptr);
|
||||
|
||||
if (wfi->mutex == nullptr)
|
||||
{
|
||||
WLog_ERR(TAG, "CreateMutex error: %lu", GetLastError());
|
||||
free(wfi);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
wfi->updateSemaphore = CreateSemaphore(nullptr, 0, 32, nullptr);
|
||||
|
||||
if (!wfi->updateSemaphore)
|
||||
{
|
||||
WLog_ERR(TAG, "CreateSemaphore error: %lu", GetLastError());
|
||||
(void)CloseHandle(wfi->mutex);
|
||||
free(wfi);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
wfi->updateThread =
|
||||
CreateThread(nullptr, 0, wf_update_thread, wfi, CREATE_SUSPENDED, nullptr);
|
||||
|
||||
if (!wfi->updateThread)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to create update thread");
|
||||
(void)CloseHandle(wfi->mutex);
|
||||
(void)CloseHandle(wfi->updateSemaphore);
|
||||
free(wfi);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
wfi->peers =
|
||||
(freerdp_peer**)calloc(FREERDP_SERVER_WIN_INFO_MAXPEERS, sizeof(freerdp_peer*));
|
||||
|
||||
if (!wfi->peers)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to allocate memory for peer");
|
||||
(void)CloseHandle(wfi->mutex);
|
||||
(void)CloseHandle(wfi->updateSemaphore);
|
||||
(void)CloseHandle(wfi->updateThread);
|
||||
free(wfi);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Set FPS
|
||||
wfi->framesPerSecond = FREERDP_SERVER_WIN_INFO_DEFAULT_FPS;
|
||||
status =
|
||||
RegOpenKeyExA(HKEY_LOCAL_MACHINE, SERVER_KEY, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
|
||||
|
||||
if (status == ERROR_SUCCESS)
|
||||
{
|
||||
if (RegQueryValueEx(hKey, _T("FramesPerSecond"), nullptr, &dwType, (BYTE*)&dwValue,
|
||||
&dwSize) == ERROR_SUCCESS)
|
||||
wfi->framesPerSecond = dwValue;
|
||||
}
|
||||
|
||||
RegCloseKey(hKey);
|
||||
// Set input toggle
|
||||
wfi->input_disabled = FALSE;
|
||||
status =
|
||||
RegOpenKeyExA(HKEY_LOCAL_MACHINE, SERVER_KEY, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
|
||||
|
||||
if (status == ERROR_SUCCESS)
|
||||
{
|
||||
if (RegQueryValueEx(hKey, _T("DisableInput"), nullptr, &dwType, (BYTE*)&dwValue,
|
||||
&dwSize) == ERROR_SUCCESS)
|
||||
{
|
||||
if (dwValue != 0)
|
||||
wfi->input_disabled = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
return wfi;
|
||||
}
|
||||
|
||||
wfInfo* wf_info_get_instance()
|
||||
{
|
||||
if (wfInfoInstance == nullptr)
|
||||
wfInfoInstance = wf_info_init();
|
||||
|
||||
return wfInfoInstance;
|
||||
}
|
||||
|
||||
BOOL wf_info_peer_register(wfInfo* wfi, wfPeerContext* context)
|
||||
{
|
||||
int peerId = 0;
|
||||
|
||||
if (!wfi || !context)
|
||||
return FALSE;
|
||||
|
||||
if (!wf_info_lock(wfi))
|
||||
return FALSE;
|
||||
|
||||
if (wfi->peerCount == FREERDP_SERVER_WIN_INFO_MAXPEERS)
|
||||
goto fail_peer_count;
|
||||
|
||||
context->info = wfi;
|
||||
|
||||
if (!(context->updateEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
|
||||
goto fail_update_event;
|
||||
|
||||
// get the offset of the top left corner of selected screen
|
||||
EnumDisplayMonitors(nullptr, nullptr, wf_info_monEnumCB, 0);
|
||||
_IDcount = 0;
|
||||
#ifdef WITH_DXGI_1_2
|
||||
|
||||
if (wfi->peerCount == 0)
|
||||
if (wf_dxgi_init(wfi) != 0)
|
||||
goto fail_driver_init;
|
||||
|
||||
#else
|
||||
|
||||
if (!wf_mirror_driver_activate(wfi))
|
||||
goto fail_driver_init;
|
||||
|
||||
#endif
|
||||
|
||||
// look through the array of peers until an empty slot
|
||||
for (int i = 0; i < FREERDP_SERVER_WIN_INFO_MAXPEERS; ++i)
|
||||
{
|
||||
// empty index will be our peer id
|
||||
if (wfi->peers[i] == nullptr)
|
||||
{
|
||||
peerId = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
wfi->peers[peerId] = ((rdpContext*)context)->peer;
|
||||
wfi->peers[peerId]->pId = peerId;
|
||||
wfi->peerCount++;
|
||||
WLog_INFO(TAG, "Registering Peer: id=%d #=%d", peerId, wfi->peerCount);
|
||||
wf_info_unlock(wfi);
|
||||
wfreerdp_server_peer_callback_event(peerId, FREERDP_SERVER_WIN_SRV_CALLBACK_EVENT_CONNECT);
|
||||
return TRUE;
|
||||
fail_driver_init:
|
||||
(void)CloseHandle(context->updateEvent);
|
||||
context->updateEvent = nullptr;
|
||||
fail_update_event:
|
||||
fail_peer_count:
|
||||
context->socketClose = TRUE;
|
||||
wf_info_unlock(wfi);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void wf_info_peer_unregister(wfInfo* wfi, wfPeerContext* context)
|
||||
{
|
||||
if (wf_info_lock(wfi))
|
||||
{
|
||||
int peerId;
|
||||
peerId = ((rdpContext*)context)->peer->pId;
|
||||
wfi->peers[peerId] = nullptr;
|
||||
wfi->peerCount--;
|
||||
(void)CloseHandle(context->updateEvent);
|
||||
WLog_INFO(TAG, "Unregistering Peer: id=%d, #=%d", peerId, wfi->peerCount);
|
||||
#ifdef WITH_DXGI_1_2
|
||||
|
||||
if (wfi->peerCount == 0)
|
||||
wf_dxgi_cleanup(wfi);
|
||||
|
||||
#endif
|
||||
wf_info_unlock(wfi);
|
||||
wfreerdp_server_peer_callback_event(peerId,
|
||||
FREERDP_SERVER_WIN_SRV_CALLBACK_EVENT_DISCONNECT);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL wf_info_have_updates(wfInfo* wfi)
|
||||
{
|
||||
#ifdef WITH_DXGI_1_2
|
||||
|
||||
if (wfi->framesWaiting == 0)
|
||||
return FALSE;
|
||||
|
||||
#else
|
||||
|
||||
if (wfi->nextUpdate == wfi->lastUpdate)
|
||||
return FALSE;
|
||||
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void wf_info_update_changes(wfInfo* wfi)
|
||||
{
|
||||
#ifdef WITH_DXGI_1_2
|
||||
wf_dxgi_nextFrame(wfi, wfi->framesPerSecond * 1000);
|
||||
#else
|
||||
GETCHANGESBUF* buf;
|
||||
buf = (GETCHANGESBUF*)wfi->changeBuffer;
|
||||
wfi->nextUpdate = buf->buffer->counter;
|
||||
#endif
|
||||
}
|
||||
|
||||
void wf_info_find_invalid_region(wfInfo* wfi)
|
||||
{
|
||||
#ifdef WITH_DXGI_1_2
|
||||
wf_dxgi_getInvalidRegion(&wfi->invalid);
|
||||
#else
|
||||
GETCHANGESBUF* buf;
|
||||
buf = (GETCHANGESBUF*)wfi->changeBuffer;
|
||||
|
||||
for (ULONG i = wfi->lastUpdate; i != wfi->nextUpdate; i = (i + 1) % MAXCHANGES_BUF)
|
||||
{
|
||||
LPRECT lpR = &buf->buffer->pointrect[i].rect;
|
||||
|
||||
// need to make sure we only get updates from the selected screen
|
||||
if ((lpR->left >= wfi->servscreen_xoffset) &&
|
||||
(lpR->right <= (wfi->servscreen_xoffset + wfi->servscreen_width)) &&
|
||||
(lpR->top >= wfi->servscreen_yoffset) &&
|
||||
(lpR->bottom <= (wfi->servscreen_yoffset + wfi->servscreen_height)))
|
||||
{
|
||||
UnionRect(&wfi->invalid, &wfi->invalid, lpR);
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (wfi->invalid.left < 0)
|
||||
wfi->invalid.left = 0;
|
||||
|
||||
if (wfi->invalid.top < 0)
|
||||
wfi->invalid.top = 0;
|
||||
|
||||
if (wfi->invalid.right >= wfi->servscreen_width)
|
||||
wfi->invalid.right = wfi->servscreen_width - 1;
|
||||
|
||||
if (wfi->invalid.bottom >= wfi->servscreen_height)
|
||||
wfi->invalid.bottom = wfi->servscreen_height - 1;
|
||||
|
||||
// WLog_DBG(TAG, "invalid region: (%"PRId32", %"PRId32"), (%"PRId32", %"PRId32")",
|
||||
// wfi->invalid.left, wfi->invalid.top, wfi->invalid.right, wfi->invalid.bottom);
|
||||
}
|
||||
|
||||
void wf_info_clear_invalid_region(wfInfo* wfi)
|
||||
{
|
||||
wfi->lastUpdate = wfi->nextUpdate;
|
||||
SetRectEmpty(&wfi->invalid);
|
||||
}
|
||||
|
||||
void wf_info_invalidate_full_screen(wfInfo* wfi)
|
||||
{
|
||||
SetRect(&wfi->invalid, 0, 0, wfi->servscreen_width, wfi->servscreen_height);
|
||||
}
|
||||
|
||||
BOOL wf_info_have_invalid_region(wfInfo* wfi)
|
||||
{
|
||||
return IsRectEmpty(&wfi->invalid);
|
||||
}
|
||||
|
||||
void wf_info_getScreenData(wfInfo* wfi, long* width, long* height, BYTE** pBits, int* pitch)
|
||||
{
|
||||
*width = (wfi->invalid.right - wfi->invalid.left);
|
||||
*height = (wfi->invalid.bottom - wfi->invalid.top);
|
||||
#ifdef WITH_DXGI_1_2
|
||||
wf_dxgi_getPixelData(wfi, pBits, pitch, &wfi->invalid);
|
||||
#else
|
||||
{
|
||||
long offset;
|
||||
GETCHANGESBUF* changes;
|
||||
changes = (GETCHANGESBUF*)wfi->changeBuffer;
|
||||
*width += 1;
|
||||
*height += 1;
|
||||
offset = (4 * wfi->invalid.left) + (wfi->invalid.top * wfi->virtscreen_width * 4);
|
||||
*pBits = ((BYTE*)(changes->Userbuffer)) + offset;
|
||||
*pitch = wfi->virtscreen_width * 4;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOL CALLBACK wf_info_monEnumCB(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor,
|
||||
LPARAM dwData)
|
||||
{
|
||||
wfInfo* wfi;
|
||||
wfi = wf_info_get_instance();
|
||||
|
||||
if (!wfi)
|
||||
return FALSE;
|
||||
|
||||
if (_IDcount == wfi->screenID)
|
||||
{
|
||||
wfi->servscreen_xoffset = lprcMonitor->left;
|
||||
wfi->servscreen_yoffset = lprcMonitor->top;
|
||||
}
|
||||
|
||||
_IDcount++;
|
||||
return TRUE;
|
||||
}
|
||||
46
third_party/FreeRDP/server/Windows/wf_info.h
vendored
Normal file
46
third_party/FreeRDP/server/Windows/wf_info.h
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Windows Server
|
||||
*
|
||||
* Copyright 2012 Corey Clayton <can.of.tuna@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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_WIN_INFO_H
|
||||
#define FREERDP_SERVER_WIN_INFO_H
|
||||
|
||||
#include "wf_interface.h"
|
||||
|
||||
#define FREERDP_SERVER_WIN_INFO_DEFAULT_FPS 24
|
||||
#define FREERDP_SERVER_WIN_INFO_MAXPEERS 32
|
||||
|
||||
WINPR_ATTR_NODISCARD BOOL wf_info_lock(wfInfo* wfi);
|
||||
WINPR_ATTR_NODISCARD BOOL wf_info_try_lock(wfInfo* wfi, DWORD dwMilliseconds);
|
||||
WINPR_ATTR_NODISCARD BOOL wf_info_unlock(wfInfo* wfi);
|
||||
|
||||
WINPR_ATTR_NODISCARD wfInfo* wf_info_get_instance(void);
|
||||
WINPR_ATTR_NODISCARD BOOL wf_info_peer_register(wfInfo* wfi, wfPeerContext* context);
|
||||
void wf_info_peer_unregister(wfInfo* wfi, wfPeerContext* context);
|
||||
|
||||
WINPR_ATTR_NODISCARD BOOL wf_info_have_updates(wfInfo* wfi);
|
||||
void wf_info_update_changes(wfInfo* wfi);
|
||||
void wf_info_find_invalid_region(wfInfo* wfi);
|
||||
void wf_info_clear_invalid_region(wfInfo* wfi);
|
||||
void wf_info_invalidate_full_screen(wfInfo* wfi);
|
||||
WINPR_ATTR_NODISCARD BOOL wf_info_have_invalid_region(wfInfo* wfi);
|
||||
void wf_info_getScreenData(wfInfo* wfi, long* width, long* height, BYTE** pBits, int* pitch);
|
||||
WINPR_ATTR_NODISCARD BOOL CALLBACK wf_info_monEnumCB(HMONITOR hMonitor, HDC hdcMonitor,
|
||||
LPRECT lprcMonitor, LPARAM dwData);
|
||||
|
||||
#endif /* FREERDP_SERVER_WIN_INFO_H */
|
||||
223
third_party/FreeRDP/server/Windows/wf_input.c
vendored
Normal file
223
third_party/FreeRDP/server/Windows/wf_input.c
vendored
Normal file
@@ -0,0 +1,223 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Windows Server
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/windows.h>
|
||||
|
||||
#include "wf_input.h"
|
||||
#include "wf_info.h"
|
||||
|
||||
BOOL wf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code)
|
||||
{
|
||||
INPUT keyboard_event;
|
||||
WINPR_UNUSED(input);
|
||||
keyboard_event.type = INPUT_KEYBOARD;
|
||||
keyboard_event.u.ki.wVk = 0;
|
||||
keyboard_event.u.ki.wScan = code;
|
||||
keyboard_event.u.ki.dwFlags = KEYEVENTF_SCANCODE;
|
||||
keyboard_event.u.ki.dwExtraInfo = 0;
|
||||
keyboard_event.u.ki.time = 0;
|
||||
|
||||
if (flags & KBD_FLAGS_RELEASE)
|
||||
keyboard_event.u.ki.dwFlags |= KEYEVENTF_KEYUP;
|
||||
|
||||
if (flags & KBD_FLAGS_EXTENDED)
|
||||
keyboard_event.u.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
|
||||
|
||||
SendInput(1, &keyboard_event, sizeof(INPUT));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL wf_peer_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
|
||||
{
|
||||
INPUT keyboard_event;
|
||||
WINPR_UNUSED(input);
|
||||
keyboard_event.type = INPUT_KEYBOARD;
|
||||
keyboard_event.u.ki.wVk = 0;
|
||||
keyboard_event.u.ki.wScan = code;
|
||||
keyboard_event.u.ki.dwFlags = KEYEVENTF_UNICODE;
|
||||
keyboard_event.u.ki.dwExtraInfo = 0;
|
||||
keyboard_event.u.ki.time = 0;
|
||||
|
||||
if (flags & KBD_FLAGS_RELEASE)
|
||||
keyboard_event.u.ki.dwFlags |= KEYEVENTF_KEYUP;
|
||||
|
||||
SendInput(1, &keyboard_event, sizeof(INPUT));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL wf_peer_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
|
||||
{
|
||||
INPUT mouse_event = WINPR_C_ARRAY_INIT;
|
||||
float width, height;
|
||||
WINPR_UNUSED(input);
|
||||
|
||||
WINPR_ASSERT(input);
|
||||
mouse_event.type = INPUT_MOUSE;
|
||||
|
||||
if (flags & PTR_FLAGS_WHEEL)
|
||||
{
|
||||
mouse_event.u.mi.dwFlags = MOUSEEVENTF_WHEEL;
|
||||
mouse_event.u.mi.mouseData = flags & WheelRotationMask;
|
||||
|
||||
if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
|
||||
mouse_event.u.mi.mouseData *= -1;
|
||||
|
||||
SendInput(1, &mouse_event, sizeof(INPUT));
|
||||
}
|
||||
else
|
||||
{
|
||||
wfInfo* wfi;
|
||||
wfi = wf_info_get_instance();
|
||||
|
||||
if (!wfi)
|
||||
return FALSE;
|
||||
|
||||
// width and height of primary screen (even in multimon setups
|
||||
width = (float)GetSystemMetrics(SM_CXSCREEN);
|
||||
height = (float)GetSystemMetrics(SM_CYSCREEN);
|
||||
x += wfi->servscreen_xoffset;
|
||||
y += wfi->servscreen_yoffset;
|
||||
mouse_event.u.mi.dx = (LONG)((float)x * (65535.0f / width));
|
||||
mouse_event.u.mi.dy = (LONG)((float)y * (65535.0f / height));
|
||||
mouse_event.u.mi.dwFlags = MOUSEEVENTF_ABSOLUTE;
|
||||
|
||||
if (flags & PTR_FLAGS_MOVE)
|
||||
{
|
||||
mouse_event.u.mi.dwFlags |= MOUSEEVENTF_MOVE;
|
||||
SendInput(1, &mouse_event, sizeof(INPUT));
|
||||
}
|
||||
|
||||
mouse_event.u.mi.dwFlags = MOUSEEVENTF_ABSOLUTE;
|
||||
|
||||
if (flags & PTR_FLAGS_BUTTON1)
|
||||
{
|
||||
if (flags & PTR_FLAGS_DOWN)
|
||||
mouse_event.u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
|
||||
else
|
||||
mouse_event.u.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
|
||||
|
||||
SendInput(1, &mouse_event, sizeof(INPUT));
|
||||
}
|
||||
else if (flags & PTR_FLAGS_BUTTON2)
|
||||
{
|
||||
if (flags & PTR_FLAGS_DOWN)
|
||||
mouse_event.u.mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
|
||||
else
|
||||
mouse_event.u.mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
|
||||
|
||||
SendInput(1, &mouse_event, sizeof(INPUT));
|
||||
}
|
||||
else if (flags & PTR_FLAGS_BUTTON3)
|
||||
{
|
||||
if (flags & PTR_FLAGS_DOWN)
|
||||
mouse_event.u.mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
|
||||
else
|
||||
mouse_event.u.mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
|
||||
|
||||
SendInput(1, &mouse_event, sizeof(INPUT));
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL wf_peer_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
|
||||
{
|
||||
if ((flags & PTR_XFLAGS_BUTTON1) || (flags & PTR_XFLAGS_BUTTON2))
|
||||
{
|
||||
INPUT mouse_event = WINPR_C_ARRAY_INIT;
|
||||
mouse_event.type = INPUT_MOUSE;
|
||||
|
||||
if (flags & PTR_FLAGS_MOVE)
|
||||
{
|
||||
float width, height;
|
||||
wfInfo* wfi;
|
||||
wfi = wf_info_get_instance();
|
||||
|
||||
if (!wfi)
|
||||
return FALSE;
|
||||
|
||||
// width and height of primary screen (even in multimon setups
|
||||
width = (float)GetSystemMetrics(SM_CXSCREEN);
|
||||
height = (float)GetSystemMetrics(SM_CYSCREEN);
|
||||
x += wfi->servscreen_xoffset;
|
||||
y += wfi->servscreen_yoffset;
|
||||
mouse_event.u.mi.dx = (LONG)((float)x * (65535.0f / width));
|
||||
mouse_event.u.mi.dy = (LONG)((float)y * (65535.0f / height));
|
||||
mouse_event.u.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
|
||||
SendInput(1, &mouse_event, sizeof(INPUT));
|
||||
}
|
||||
|
||||
mouse_event.u.mi.dx = mouse_event.u.mi.dy = mouse_event.u.mi.dwFlags = 0;
|
||||
|
||||
if (flags & PTR_XFLAGS_DOWN)
|
||||
mouse_event.u.mi.dwFlags |= MOUSEEVENTF_XDOWN;
|
||||
else
|
||||
mouse_event.u.mi.dwFlags |= MOUSEEVENTF_XUP;
|
||||
|
||||
if (flags & PTR_XFLAGS_BUTTON1)
|
||||
mouse_event.u.mi.mouseData = XBUTTON1;
|
||||
else if (flags & PTR_XFLAGS_BUTTON2)
|
||||
mouse_event.u.mi.mouseData = XBUTTON2;
|
||||
|
||||
SendInput(1, &mouse_event, sizeof(INPUT));
|
||||
}
|
||||
else
|
||||
{
|
||||
wf_peer_mouse_event(input, flags, x, y);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL wf_peer_keyboard_event_dummy(rdpInput* input, UINT16 flags, UINT8 code)
|
||||
{
|
||||
WINPR_UNUSED(input);
|
||||
WINPR_UNUSED(flags);
|
||||
WINPR_UNUSED(code);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL wf_peer_unicode_keyboard_event_dummy(rdpInput* input, UINT16 flags, UINT16 code)
|
||||
{
|
||||
WINPR_UNUSED(input);
|
||||
WINPR_UNUSED(flags);
|
||||
WINPR_UNUSED(code);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL wf_peer_mouse_event_dummy(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
|
||||
{
|
||||
WINPR_UNUSED(input);
|
||||
WINPR_UNUSED(flags);
|
||||
WINPR_UNUSED(x);
|
||||
WINPR_UNUSED(y);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL wf_peer_extended_mouse_event_dummy(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
|
||||
{
|
||||
WINPR_UNUSED(input);
|
||||
WINPR_UNUSED(flags);
|
||||
WINPR_UNUSED(x);
|
||||
WINPR_UNUSED(y);
|
||||
return TRUE;
|
||||
}
|
||||
41
third_party/FreeRDP/server/Windows/wf_input.h
vendored
Normal file
41
third_party/FreeRDP/server/Windows/wf_input.h
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Windows Server
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_WIN_INPUT_H
|
||||
#define FREERDP_SERVER_WIN_INPUT_H
|
||||
|
||||
#include "wf_interface.h"
|
||||
|
||||
WINPR_ATTR_NODISCARD BOOL wf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code);
|
||||
WINPR_ATTR_NODISCARD BOOL wf_peer_unicode_keyboard_event(rdpInput* input, UINT16 flags,
|
||||
UINT16 code);
|
||||
WINPR_ATTR_NODISCARD BOOL wf_peer_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y);
|
||||
WINPR_ATTR_NODISCARD BOOL wf_peer_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x,
|
||||
UINT16 y);
|
||||
|
||||
// dummy versions
|
||||
WINPR_ATTR_NODISCARD BOOL wf_peer_keyboard_event_dummy(rdpInput* input, UINT16 flags, UINT8 code);
|
||||
WINPR_ATTR_NODISCARD BOOL wf_peer_unicode_keyboard_event_dummy(rdpInput* input, UINT16 flags,
|
||||
UINT16 code);
|
||||
WINPR_ATTR_NODISCARD BOOL wf_peer_mouse_event_dummy(rdpInput* input, UINT16 flags, UINT16 x,
|
||||
UINT16 y);
|
||||
WINPR_ATTR_NODISCARD BOOL wf_peer_extended_mouse_event_dummy(rdpInput* input, UINT16 flags,
|
||||
UINT16 x, UINT16 y);
|
||||
|
||||
#endif /* FREERDP_SERVER_WIN_INPUT_H */
|
||||
342
third_party/FreeRDP/server/Windows/wf_interface.c
vendored
Normal file
342
third_party/FreeRDP/server/Windows/wf_interface.c
vendored
Normal file
@@ -0,0 +1,342 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Windows Server
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2012 Corey Clayton <can.of.tuna@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 <freerdp/config.h>
|
||||
|
||||
#include <winpr/tchar.h>
|
||||
#include <winpr/windows.h>
|
||||
#include <winpr/winsock.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/listener.h>
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/channels/wtsvc.h>
|
||||
#include <freerdp/channels/channels.h>
|
||||
#include <freerdp/build-config.h>
|
||||
|
||||
#include "wf_peer.h"
|
||||
#include "wf_settings.h"
|
||||
#include "wf_info.h"
|
||||
|
||||
#include "wf_interface.h"
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG SERVER_TAG("windows")
|
||||
|
||||
#define SERVER_KEY "Software\\" FREERDP_VENDOR_STRING "\\" FREERDP_PRODUCT_STRING "\\Server"
|
||||
|
||||
static cbCallback cbEvent = nullptr;
|
||||
|
||||
int get_screen_info(int id, _TCHAR* name, size_t length, int* width, int* height, int* bpp)
|
||||
{
|
||||
DISPLAY_DEVICE dd = WINPR_C_ARRAY_INIT;
|
||||
|
||||
dd.cb = sizeof(DISPLAY_DEVICE);
|
||||
|
||||
if (EnumDisplayDevices(nullptr, id, &dd, 0) != 0)
|
||||
{
|
||||
HDC dc;
|
||||
|
||||
if (name != nullptr)
|
||||
_stprintf_s(name, length, _T("%s (%s)"), dd.DeviceName, dd.DeviceString);
|
||||
|
||||
dc = CreateDC(dd.DeviceName, nullptr, nullptr, nullptr);
|
||||
*width = GetDeviceCaps(dc, HORZRES);
|
||||
*height = GetDeviceCaps(dc, VERTRES);
|
||||
*bpp = GetDeviceCaps(dc, BITSPIXEL);
|
||||
// ReleaseDC(nullptr, dc);
|
||||
DeleteDC(dc);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void set_screen_id(int id)
|
||||
{
|
||||
wfInfo* wfi;
|
||||
|
||||
wfi = wf_info_get_instance();
|
||||
if (!wfi)
|
||||
return;
|
||||
wfi->screenID = id;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static DWORD WINAPI wf_server_main_loop(LPVOID lpParam)
|
||||
{
|
||||
freerdp_listener* instance;
|
||||
wfInfo* wfi;
|
||||
|
||||
wfi = wf_info_get_instance();
|
||||
if (!wfi)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get instance");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wfi->force_all_disconnect = FALSE;
|
||||
|
||||
instance = (freerdp_listener*)lpParam;
|
||||
WINPR_ASSERT(instance);
|
||||
WINPR_ASSERT(instance->GetEventHandles);
|
||||
WINPR_ASSERT(instance->CheckFileDescriptor);
|
||||
|
||||
while (wfi->force_all_disconnect == FALSE)
|
||||
{
|
||||
DWORD status;
|
||||
HANDLE handles[MAXIMUM_WAIT_OBJECTS] = WINPR_C_ARRAY_INIT;
|
||||
DWORD count = instance->GetEventHandles(instance, handles, ARRAYSIZE(handles));
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get FreeRDP file descriptor");
|
||||
break;
|
||||
}
|
||||
|
||||
status = WaitForMultipleObjects(count, handles, FALSE, INFINITE);
|
||||
if (status == WAIT_FAILED)
|
||||
{
|
||||
WLog_ERR(TAG, "WaitForMultipleObjects failed");
|
||||
break;
|
||||
}
|
||||
|
||||
if (instance->CheckFileDescriptor(instance) != TRUE)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
WLog_INFO(TAG, "wf_server_main_loop terminating");
|
||||
instance->Close(instance);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL wfreerdp_server_start(wfServer* server)
|
||||
{
|
||||
freerdp_listener* instance;
|
||||
|
||||
server->instance = freerdp_listener_new();
|
||||
server->instance->PeerAccepted = wf_peer_accepted;
|
||||
instance = server->instance;
|
||||
|
||||
wf_settings_read_dword(HKEY_LOCAL_MACHINE, SERVER_KEY, _T("DefaultPort"), &server->port);
|
||||
|
||||
if (!instance->Open(instance, nullptr, (UINT16)server->port))
|
||||
return FALSE;
|
||||
|
||||
if (!(server->thread =
|
||||
CreateThread(nullptr, 0, wf_server_main_loop, (void*)instance, 0, nullptr)))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL wfreerdp_server_stop(wfServer* server)
|
||||
{
|
||||
wfInfo* wfi;
|
||||
|
||||
wfi = wf_info_get_instance();
|
||||
if (!wfi)
|
||||
return FALSE;
|
||||
WLog_INFO(TAG, "Stopping server");
|
||||
wfi->force_all_disconnect = TRUE;
|
||||
server->instance->Close(server->instance);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
wfServer* wfreerdp_server_new()
|
||||
{
|
||||
WSADATA wsaData;
|
||||
wfServer* server;
|
||||
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
|
||||
return nullptr;
|
||||
|
||||
server = (wfServer*)calloc(1, sizeof(wfServer));
|
||||
|
||||
if (server)
|
||||
{
|
||||
server->port = 3389;
|
||||
}
|
||||
|
||||
WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi());
|
||||
|
||||
cbEvent = nullptr;
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
void wfreerdp_server_free(wfServer* server)
|
||||
{
|
||||
free(server);
|
||||
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
BOOL wfreerdp_server_is_running(wfServer* server)
|
||||
{
|
||||
DWORD tStatus;
|
||||
BOOL bRet;
|
||||
|
||||
bRet = GetExitCodeThread(server->thread, &tStatus);
|
||||
if (bRet == 0)
|
||||
{
|
||||
WLog_ERR(TAG, "Error in call to GetExitCodeThread");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (tStatus == STILL_ACTIVE)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
UINT32 wfreerdp_server_num_peers()
|
||||
{
|
||||
wfInfo* wfi;
|
||||
|
||||
wfi = wf_info_get_instance();
|
||||
if (!wfi)
|
||||
return -1;
|
||||
return wfi->peerCount;
|
||||
}
|
||||
|
||||
UINT32 wfreerdp_server_get_peer_hostname(int pId, wchar_t* dstStr)
|
||||
{
|
||||
wfInfo* wfi;
|
||||
freerdp_peer* peer;
|
||||
|
||||
wfi = wf_info_get_instance();
|
||||
if (!wfi)
|
||||
return 0;
|
||||
peer = wfi->peers[pId];
|
||||
|
||||
if (peer)
|
||||
{
|
||||
UINT32 sLen;
|
||||
|
||||
sLen = strnlen_s(peer->hostname, 50);
|
||||
swprintf(dstStr, 50, L"%hs", peer->hostname);
|
||||
return sLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_WARN(TAG, "nonexistent peer id=%d", pId);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL wfreerdp_server_peer_is_local(int pId)
|
||||
{
|
||||
wfInfo* wfi;
|
||||
freerdp_peer* peer;
|
||||
|
||||
wfi = wf_info_get_instance();
|
||||
if (!wfi)
|
||||
return FALSE;
|
||||
peer = wfi->peers[pId];
|
||||
|
||||
if (peer)
|
||||
{
|
||||
return peer->local;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL wfreerdp_server_peer_is_connected(int pId)
|
||||
{
|
||||
wfInfo* wfi;
|
||||
freerdp_peer* peer;
|
||||
|
||||
wfi = wf_info_get_instance();
|
||||
if (!wfi)
|
||||
return FALSE;
|
||||
peer = wfi->peers[pId];
|
||||
|
||||
if (peer)
|
||||
{
|
||||
return peer->connected;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL wfreerdp_server_peer_is_activated(int pId)
|
||||
{
|
||||
wfInfo* wfi;
|
||||
freerdp_peer* peer;
|
||||
|
||||
wfi = wf_info_get_instance();
|
||||
if (!wfi)
|
||||
return FALSE;
|
||||
peer = wfi->peers[pId];
|
||||
|
||||
if (peer)
|
||||
{
|
||||
return peer->activated;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL wfreerdp_server_peer_is_authenticated(int pId)
|
||||
{
|
||||
wfInfo* wfi;
|
||||
freerdp_peer* peer;
|
||||
|
||||
wfi = wf_info_get_instance();
|
||||
if (!wfi)
|
||||
return FALSE;
|
||||
peer = wfi->peers[pId];
|
||||
|
||||
if (peer)
|
||||
{
|
||||
return peer->authenticated;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void wfreerdp_server_register_callback_event(cbCallback cb)
|
||||
{
|
||||
cbEvent = cb;
|
||||
}
|
||||
|
||||
void wfreerdp_server_peer_callback_event(int pId, UINT32 eType)
|
||||
{
|
||||
if (cbEvent)
|
||||
cbEvent(pId, eType);
|
||||
}
|
||||
141
third_party/FreeRDP/server/Windows/wf_interface.h
vendored
Normal file
141
third_party/FreeRDP/server/Windows/wf_interface.h
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Client
|
||||
* FreeRDP Windows Server
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2012 Corey Clayton <can.of.tuna@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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_WIN_INTERFACE_H
|
||||
#define FREERDP_SERVER_WIN_INTERFACE_H
|
||||
|
||||
#include <winpr/windows.h>
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/listener.h>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/codec/rfx.h>
|
||||
|
||||
#include <freerdp/server/rdpsnd.h>
|
||||
|
||||
#if _WIN32_WINNT >= 0x0602
|
||||
#define WITH_DXGI_1_2 1
|
||||
#endif
|
||||
|
||||
#define FREERDP_SERVER_WIN_SRV_CALLBACK_EVENT_CONNECT 1
|
||||
#define FREERDP_SERVER_WIN_SRV_CALLBACK_EVENT_DISCONNECT 2
|
||||
#define FREERDP_SERVER_WIN_SRV_CALLBACK_EVENT_ACTIVATE 4
|
||||
#define FREERDP_SERVER_WIN_SRV_CALLBACK_EVENT_AUTH 8
|
||||
|
||||
typedef struct wf_info wfInfo;
|
||||
typedef struct wf_peer_context wfPeerContext;
|
||||
|
||||
struct wf_info
|
||||
{
|
||||
wStream* s;
|
||||
|
||||
// screen and monitor info
|
||||
int screenID;
|
||||
int virtscreen_width;
|
||||
int virtscreen_height;
|
||||
int servscreen_width;
|
||||
int servscreen_height;
|
||||
int servscreen_xoffset;
|
||||
int servscreen_yoffset;
|
||||
|
||||
int frame_idx;
|
||||
int bitsPerPixel;
|
||||
HDC driverDC;
|
||||
int peerCount;
|
||||
int activePeerCount;
|
||||
void* changeBuffer;
|
||||
int framesPerSecond;
|
||||
LPTSTR deviceKey;
|
||||
TCHAR deviceName[32];
|
||||
freerdp_peer** peers;
|
||||
BOOL mirrorDriverActive;
|
||||
UINT framesWaiting;
|
||||
|
||||
HANDLE snd_mutex;
|
||||
BOOL snd_stop;
|
||||
AUDIO_FORMAT* agreed_format;
|
||||
|
||||
RECT invalid;
|
||||
HANDLE mutex;
|
||||
BOOL updatePending;
|
||||
HANDLE updateEvent;
|
||||
HANDLE updateThread;
|
||||
HANDLE updateSemaphore;
|
||||
RFX_CONTEXT* rfx_context;
|
||||
unsigned long lastUpdate;
|
||||
unsigned long nextUpdate;
|
||||
SURFACE_BITS_COMMAND cmd;
|
||||
|
||||
BOOL input_disabled;
|
||||
BOOL force_all_disconnect;
|
||||
};
|
||||
|
||||
struct wf_peer_context
|
||||
{
|
||||
rdpContext _p;
|
||||
|
||||
wfInfo* info;
|
||||
int frame_idx;
|
||||
HANDLE updateEvent;
|
||||
BOOL socketClose;
|
||||
HANDLE socketEvent;
|
||||
HANDLE socketThread;
|
||||
HANDLE socketSemaphore;
|
||||
|
||||
HANDLE vcm;
|
||||
RdpsndServerContext* rdpsnd;
|
||||
};
|
||||
|
||||
struct wf_server
|
||||
{
|
||||
DWORD port;
|
||||
HANDLE thread;
|
||||
freerdp_listener* instance;
|
||||
};
|
||||
typedef struct wf_server wfServer;
|
||||
|
||||
typedef void(__stdcall* cbCallback)(int, UINT32);
|
||||
|
||||
FREERDP_API WINPR_ATTR_NODISCARD int get_screen_info(int id, _TCHAR* name, size_t length, int* w,
|
||||
int* h, int* b);
|
||||
FREERDP_API void set_screen_id(int id);
|
||||
|
||||
FREERDP_API WINPR_ATTR_NODISCARD BOOL wfreerdp_server_start(wfServer* server);
|
||||
FREERDP_API WINPR_ATTR_NODISCARD BOOL wfreerdp_server_stop(wfServer* server);
|
||||
|
||||
FREERDP_API WINPR_ATTR_NODISCARD wfServer* wfreerdp_server_new(void);
|
||||
FREERDP_API void wfreerdp_server_free(wfServer* server);
|
||||
|
||||
FREERDP_API WINPR_ATTR_NODISCARD BOOL wfreerdp_server_is_running(wfServer* server);
|
||||
|
||||
FREERDP_API WINPR_ATTR_NODISCARD UINT32 wfreerdp_server_num_peers(void);
|
||||
FREERDP_API WINPR_ATTR_NODISCARD UINT32 wfreerdp_server_get_peer_hostname(int pId, wchar_t* dstStr);
|
||||
FREERDP_API WINPR_ATTR_NODISCARD BOOL wfreerdp_server_peer_is_local(int pId);
|
||||
FREERDP_API WINPR_ATTR_NODISCARD BOOL wfreerdp_server_peer_is_connected(int pId);
|
||||
FREERDP_API WINPR_ATTR_NODISCARD BOOL wfreerdp_server_peer_is_activated(int pId);
|
||||
FREERDP_API WINPR_ATTR_NODISCARD BOOL wfreerdp_server_peer_is_authenticated(int pId);
|
||||
|
||||
FREERDP_API void wfreerdp_server_register_callback_event(cbCallback cb);
|
||||
|
||||
void wfreerdp_server_peer_callback_event(int pId, UINT32 eType);
|
||||
|
||||
#endif /* FREERDP_SERVER_WIN_INTERFACE_H */
|
||||
362
third_party/FreeRDP/server/Windows/wf_mirage.c
vendored
Normal file
362
third_party/FreeRDP/server/Windows/wf_mirage.c
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Windows Server
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2012-2013 Corey Clayton <can.of.tuna@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/tchar.h>
|
||||
#include <winpr/windows.h>
|
||||
|
||||
#include "wf_mirage.h"
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG SERVER_TAG("Windows.mirror")
|
||||
|
||||
#define DEVICE_KEY_PREFIX _T("\\Registry\\Machine\\")
|
||||
/*
|
||||
This function will iterate over the loaded display devices until it finds
|
||||
the mirror device we want to load. If found, it will then copy the registry
|
||||
key corresponding to the device to the wfi and returns TRUE. Otherwise
|
||||
the function returns FALSE.
|
||||
*/
|
||||
BOOL wf_mirror_driver_find_display_device(wfInfo* wfi)
|
||||
{
|
||||
BOOL result;
|
||||
BOOL devFound;
|
||||
DWORD deviceNumber;
|
||||
DISPLAY_DEVICE deviceInfo;
|
||||
devFound = FALSE;
|
||||
deviceNumber = 0;
|
||||
deviceInfo.cb = sizeof(deviceInfo);
|
||||
|
||||
while (result = EnumDisplayDevices(nullptr, deviceNumber, &deviceInfo, 0))
|
||||
{
|
||||
if (_tcscmp(deviceInfo.DeviceString, _T("Mirage Driver")) == 0)
|
||||
{
|
||||
int deviceKeyLength;
|
||||
int deviceKeyPrefixLength;
|
||||
deviceKeyPrefixLength = _tcslen(DEVICE_KEY_PREFIX);
|
||||
|
||||
if (_tcsnicmp(deviceInfo.DeviceKey, DEVICE_KEY_PREFIX, deviceKeyPrefixLength) == 0)
|
||||
{
|
||||
deviceKeyLength = _tcslen(deviceInfo.DeviceKey) - deviceKeyPrefixLength;
|
||||
wfi->deviceKey = (LPTSTR)malloc((deviceKeyLength + 1) * sizeof(TCHAR));
|
||||
|
||||
if (!wfi->deviceKey)
|
||||
return FALSE;
|
||||
|
||||
_tcsncpy_s(wfi->deviceKey, deviceKeyLength + 1,
|
||||
&deviceInfo.DeviceKey[deviceKeyPrefixLength], deviceKeyLength);
|
||||
}
|
||||
|
||||
_tcsncpy_s(wfi->deviceName, 32, deviceInfo.DeviceName, _tcslen(deviceInfo.DeviceName));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
deviceNumber++;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will attempt to access the the windows registry using the device
|
||||
* key stored in the current wfi. It will attempt to read the value of the
|
||||
* "Attach.ToDesktop" subkey and will return TRUE if the value is already set to
|
||||
* val. If unable to read the subkey, this function will return FALSE. If the
|
||||
* subkey is not set to val it will then attempt to set it to val and return TRUE. If
|
||||
* unsuccessful or an unexpected value is encountered, the function returns
|
||||
* FALSE.
|
||||
*/
|
||||
|
||||
BOOL wf_mirror_driver_display_device_attach(wfInfo* wfi, DWORD mode)
|
||||
{
|
||||
HKEY hKey;
|
||||
LONG status;
|
||||
DWORD dwType;
|
||||
DWORD dwSize;
|
||||
DWORD dwValue;
|
||||
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, wfi->deviceKey, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY,
|
||||
&hKey);
|
||||
|
||||
if (status != ERROR_SUCCESS)
|
||||
{
|
||||
WLog_DBG(TAG, "Error opening RegKey: status=0x%08lX", status);
|
||||
|
||||
if (status == ERROR_ACCESS_DENIED)
|
||||
WLog_DBG(TAG, "access denied. Do you have admin privileges?");
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
dwSize = sizeof(DWORD);
|
||||
status =
|
||||
RegQueryValueEx(hKey, _T("Attach.ToDesktop"), nullptr, &dwType, (BYTE*)&dwValue, &dwSize);
|
||||
|
||||
if (status != ERROR_SUCCESS)
|
||||
{
|
||||
WLog_DBG(TAG, "Error querying RegKey: status=0x%08lX", status);
|
||||
|
||||
if (status == ERROR_ACCESS_DENIED)
|
||||
WLog_DBG(TAG, "access denied. Do you have admin privileges?");
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (dwValue ^ mode) // only if we want to change modes
|
||||
{
|
||||
dwValue = mode;
|
||||
dwSize = sizeof(DWORD);
|
||||
status = RegSetValueEx(hKey, _T("Attach.ToDesktop"), 0, REG_DWORD, (BYTE*)&dwValue, dwSize);
|
||||
|
||||
if (status != ERROR_SUCCESS)
|
||||
{
|
||||
WLog_DBG(TAG, "Error writing registry key: %ld", status);
|
||||
|
||||
if (status == ERROR_ACCESS_DENIED)
|
||||
WLog_DBG(TAG, "access denied. Do you have admin privileges?");
|
||||
|
||||
WLog_DBG(TAG, "");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void wf_mirror_driver_print_display_change_status(LONG status)
|
||||
{
|
||||
TCHAR disp_change[64];
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case DISP_CHANGE_SUCCESSFUL:
|
||||
_tcscpy(disp_change, _T("DISP_CHANGE_SUCCESSFUL"));
|
||||
break;
|
||||
|
||||
case DISP_CHANGE_BADDUALVIEW:
|
||||
_tcscpy(disp_change, _T("DISP_CHANGE_BADDUALVIEW"));
|
||||
break;
|
||||
|
||||
case DISP_CHANGE_BADFLAGS:
|
||||
_tcscpy(disp_change, _T("DISP_CHANGE_BADFLAGS"));
|
||||
break;
|
||||
|
||||
case DISP_CHANGE_BADMODE:
|
||||
_tcscpy(disp_change, _T("DISP_CHANGE_BADMODE"));
|
||||
break;
|
||||
|
||||
case DISP_CHANGE_BADPARAM:
|
||||
_tcscpy(disp_change, _T("DISP_CHANGE_BADPARAM"));
|
||||
break;
|
||||
|
||||
case DISP_CHANGE_FAILED:
|
||||
_tcscpy(disp_change, _T("DISP_CHANGE_FAILED"));
|
||||
break;
|
||||
|
||||
case DISP_CHANGE_NOTUPDATED:
|
||||
_tcscpy(disp_change, _T("DISP_CHANGE_NOTUPDATED"));
|
||||
break;
|
||||
|
||||
case DISP_CHANGE_RESTART:
|
||||
_tcscpy(disp_change, _T("DISP_CHANGE_RESTART"));
|
||||
break;
|
||||
|
||||
default:
|
||||
_tcscpy(disp_change, _T("DISP_CHANGE_UNKNOWN"));
|
||||
break;
|
||||
}
|
||||
|
||||
if (status != DISP_CHANGE_SUCCESSFUL)
|
||||
WLog_ERR(TAG, "ChangeDisplaySettingsEx() failed with %s (%ld)", disp_change, status);
|
||||
else
|
||||
WLog_INFO(TAG, "ChangeDisplaySettingsEx() succeeded with %s (%ld)", disp_change, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will attempt to apply the currently configured display settings
|
||||
* in the registry to the display driver. It will return TRUE if successful
|
||||
* otherwise it returns FALSE.
|
||||
* If mode is MIRROR_UNLOAD then the the driver will be asked to remove itself.
|
||||
*/
|
||||
|
||||
BOOL wf_mirror_driver_update(wfInfo* wfi, int mode)
|
||||
{
|
||||
BOOL status;
|
||||
DWORD* extHdr;
|
||||
WORD drvExtraSaved;
|
||||
DEVMODE* deviceMode;
|
||||
LONG disp_change_status;
|
||||
DWORD dmf_devmodewext_magic_sig = 0xDF20C0DE;
|
||||
|
||||
if ((mode != MIRROR_LOAD) && (mode != MIRROR_UNLOAD))
|
||||
{
|
||||
WLog_DBG(TAG, "Invalid mirror mode!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
deviceMode = (DEVMODE*)malloc(sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX);
|
||||
|
||||
if (!deviceMode)
|
||||
return FALSE;
|
||||
|
||||
deviceMode->dmDriverExtra = 2 * sizeof(DWORD);
|
||||
extHdr = (DWORD*)((BYTE*)&deviceMode + sizeof(DEVMODE));
|
||||
extHdr[0] = dmf_devmodewext_magic_sig;
|
||||
extHdr[1] = 0;
|
||||
drvExtraSaved = deviceMode->dmDriverExtra;
|
||||
memset(deviceMode, 0, sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX);
|
||||
deviceMode->dmSize = sizeof(DEVMODE);
|
||||
deviceMode->dmDriverExtra = drvExtraSaved;
|
||||
|
||||
if (mode == MIRROR_LOAD)
|
||||
{
|
||||
wfi->virtscreen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
|
||||
wfi->virtscreen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
|
||||
deviceMode->dmPelsWidth = wfi->virtscreen_width;
|
||||
deviceMode->dmPelsHeight = wfi->virtscreen_height;
|
||||
deviceMode->dmBitsPerPel = wfi->bitsPerPixel;
|
||||
deviceMode->u.s2.dmPosition.x = wfi->servscreen_xoffset;
|
||||
deviceMode->u.s2.dmPosition.y = wfi->servscreen_yoffset;
|
||||
}
|
||||
|
||||
deviceMode->dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION;
|
||||
_tcsncpy_s(deviceMode->dmDeviceName, 32, wfi->deviceName, _tcslen(wfi->deviceName));
|
||||
disp_change_status =
|
||||
ChangeDisplaySettingsEx(wfi->deviceName, deviceMode, nullptr, CDS_UPDATEREGISTRY, nullptr);
|
||||
status = (disp_change_status == DISP_CHANGE_SUCCESSFUL) ? TRUE : FALSE;
|
||||
|
||||
if (!status)
|
||||
wf_mirror_driver_print_display_change_status(disp_change_status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
BOOL wf_mirror_driver_map_memory(wfInfo* wfi)
|
||||
{
|
||||
int status;
|
||||
wfi->driverDC = CreateDC(wfi->deviceName, nullptr, nullptr, nullptr);
|
||||
|
||||
if (wfi->driverDC == nullptr)
|
||||
{
|
||||
WLog_ERR(TAG, "Could not create device driver context!");
|
||||
{
|
||||
LPVOID lpMsgBuf;
|
||||
DWORD dw = GetLastError();
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf,
|
||||
0, nullptr);
|
||||
// Display the error message and exit the process
|
||||
WLog_ERR(TAG, "CreateDC failed on device [%s] with error %lu: %s", wfi->deviceName, dw,
|
||||
lpMsgBuf);
|
||||
LocalFree(lpMsgBuf);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wfi->changeBuffer = calloc(1, sizeof(GETCHANGESBUF));
|
||||
|
||||
if (!wfi->changeBuffer)
|
||||
return FALSE;
|
||||
|
||||
status = ExtEscape(wfi->driverDC, dmf_esc_usm_pipe_map, 0, 0, sizeof(GETCHANGESBUF),
|
||||
(LPSTR)wfi->changeBuffer);
|
||||
|
||||
if (status <= 0)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to map shared memory from the driver! code %d", status);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Unmap the shared memory and release the DC */
|
||||
|
||||
BOOL wf_mirror_driver_cleanup(wfInfo* wfi)
|
||||
{
|
||||
int status;
|
||||
status = ExtEscape(wfi->driverDC, dmf_esc_usm_pipe_unmap, sizeof(GETCHANGESBUF),
|
||||
(LPSTR)wfi->changeBuffer, 0, 0);
|
||||
|
||||
if (status <= 0)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to unmap shared memory from the driver! code %d", status);
|
||||
}
|
||||
|
||||
if (wfi->driverDC != nullptr)
|
||||
{
|
||||
status = DeleteDC(wfi->driverDC);
|
||||
|
||||
if (status == 0)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to release DC!");
|
||||
}
|
||||
}
|
||||
|
||||
free(wfi->changeBuffer);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL wf_mirror_driver_activate(wfInfo* wfi)
|
||||
{
|
||||
if (!wfi->mirrorDriverActive)
|
||||
{
|
||||
WLog_DBG(TAG, "Activating Mirror Driver");
|
||||
|
||||
if (wf_mirror_driver_find_display_device(wfi) == FALSE)
|
||||
{
|
||||
WLog_DBG(TAG, "Could not find dfmirage mirror driver! Is it installed?");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (wf_mirror_driver_display_device_attach(wfi, 1) == FALSE)
|
||||
{
|
||||
WLog_DBG(TAG, "Could not attach display device!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (wf_mirror_driver_update(wfi, MIRROR_LOAD) == FALSE)
|
||||
{
|
||||
WLog_DBG(TAG, "could not update system with new display settings!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (wf_mirror_driver_map_memory(wfi) == FALSE)
|
||||
{
|
||||
WLog_DBG(TAG, "Unable to map memory for mirror driver!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wfi->mirrorDriverActive = TRUE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void wf_mirror_driver_deactivate(wfInfo* wfi)
|
||||
{
|
||||
if (wfi->mirrorDriverActive)
|
||||
{
|
||||
WLog_DBG(TAG, "Deactivating Mirror Driver");
|
||||
wf_mirror_driver_cleanup(wfi);
|
||||
wf_mirror_driver_display_device_attach(wfi, 0);
|
||||
wf_mirror_driver_update(wfi, MIRROR_UNLOAD);
|
||||
wfi->mirrorDriverActive = FALSE;
|
||||
}
|
||||
}
|
||||
219
third_party/FreeRDP/server/Windows/wf_mirage.h
vendored
Normal file
219
third_party/FreeRDP/server/Windows/wf_mirage.h
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Windows Server
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2012-2013 Corey Clayton <can.of.tuna@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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_WIN_MIRAGE_H
|
||||
#define FREERDP_SERVER_WIN_MIRAGE_H
|
||||
|
||||
#include "wf_interface.h"
|
||||
|
||||
enum
|
||||
{
|
||||
MIRROR_LOAD = 0,
|
||||
MIRROR_UNLOAD = 1
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DMF_ESCAPE_BASE_1_VB = 1030,
|
||||
DMF_ESCAPE_BASE_2_VB = 1026,
|
||||
DMF_ESCAPE_BASE_3_VB = 24
|
||||
};
|
||||
|
||||
#ifdef _WIN64
|
||||
|
||||
#define CLIENT_64BIT 0x8000
|
||||
|
||||
enum
|
||||
{
|
||||
DMF_ESCAPE_BASE_1 = CLIENT_64BIT | DMF_ESCAPE_BASE_1_VB,
|
||||
DMF_ESCAPE_BASE_2 = CLIENT_64BIT | DMF_ESCAPE_BASE_2_VB,
|
||||
DMF_ESCAPE_BASE_3 = CLIENT_64BIT | DMF_ESCAPE_BASE_3_VB,
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
enum
|
||||
{
|
||||
DMF_ESCAPE_BASE_1 = DMF_ESCAPE_BASE_1_VB,
|
||||
DMF_ESCAPE_BASE_2 = DMF_ESCAPE_BASE_2_VB,
|
||||
DMF_ESCAPE_BASE_3 = DMF_ESCAPE_BASE_3_VB,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
dmf_esc_qry_ver_info = DMF_ESCAPE_BASE_2 + 0,
|
||||
dmf_esc_usm_pipe_map = DMF_ESCAPE_BASE_1 + 0,
|
||||
dmf_esc_usm_pipe_unmap = DMF_ESCAPE_BASE_1 + 1,
|
||||
dmf_esc_test = DMF_ESCAPE_BASE_1 + 20,
|
||||
dmf_esc_usm_pipe_mapping_test = DMF_ESCAPE_BASE_1 + 21,
|
||||
dmf_esc_pointer_shape_get = DMF_ESCAPE_BASE_3,
|
||||
|
||||
} dmf_escape;
|
||||
|
||||
#define CLIP_LIMIT 50
|
||||
#define MAXCHANGES_BUF 20000
|
||||
|
||||
typedef enum
|
||||
{
|
||||
dmf_dfo_IGNORE = 0,
|
||||
dmf_dfo_FROM_SCREEN = 1,
|
||||
dmf_dfo_FROM_DIB = 2,
|
||||
dmf_dfo_TO_SCREEN = 3,
|
||||
dmf_dfo_SCREEN_SCREEN = 11,
|
||||
dmf_dfo_BLIT = 12,
|
||||
dmf_dfo_SOLIDFILL = 13,
|
||||
dmf_dfo_BLEND = 14,
|
||||
dmf_dfo_TRANS = 15,
|
||||
dmf_dfo_PLG = 17,
|
||||
dmf_dfo_TEXTOUT = 18,
|
||||
dmf_dfo_Ptr_Shape = 19,
|
||||
dmf_dfo_Ptr_Engage = 48,
|
||||
dmf_dfo_Ptr_Avert = 49,
|
||||
dmf_dfn_assert_on = 64,
|
||||
dmf_dfn_assert_off = 65,
|
||||
} dmf_UpdEvent;
|
||||
|
||||
#define NOCACHE 1
|
||||
#define OLDCACHE 2
|
||||
#define NEWCACHE 3
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG type;
|
||||
RECT rect;
|
||||
#ifndef DFMIRAGE_LEAN
|
||||
RECT origrect;
|
||||
POINT point;
|
||||
ULONG color;
|
||||
ULONG refcolor;
|
||||
#endif
|
||||
} CHANGES_RECORD;
|
||||
|
||||
typedef CHANGES_RECORD* PCHANGES_RECORD;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG counter;
|
||||
CHANGES_RECORD pointrect[MAXCHANGES_BUF];
|
||||
} CHANGES_BUF;
|
||||
|
||||
#define EXT_DEVMODE_SIZE_MAX 3072
|
||||
#define DMF_PIPE_SEC_SIZE_DEFAULT ALIGN64K(sizeof(CHANGES_BUF))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CHANGES_BUF* buffer;
|
||||
PVOID Userbuffer;
|
||||
} GETCHANGESBUF;
|
||||
|
||||
#define dmf_sprb_ERRORMASK 0x07FF
|
||||
#define dmf_sprb_STRICTSESSION_AFF 0x1FFF
|
||||
|
||||
typedef enum
|
||||
{
|
||||
dmf_sprb_internal_error = 0x0001,
|
||||
dmf_sprb_miniport_gen_error = 0x0004,
|
||||
dmf_sprb_memory_alloc_failed = 0x0008,
|
||||
dmf_sprb_pipe_buff_overflow = 0x0010,
|
||||
dmf_sprb_pipe_buff_insufficient = 0x0020,
|
||||
dmf_sprb_pipe_not_ready = 0x0040,
|
||||
dmf_sprb_gdi_err = 0x0100,
|
||||
dmf_sprb_owner_died = 0x0400,
|
||||
dmf_sprb_tgtwnd_gone = 0x0800,
|
||||
dmf_sprb_pdev_detached = 0x2000,
|
||||
} dmf_session_prob_status;
|
||||
|
||||
#define DMF_ESC_RET_FAILF 0x80000000
|
||||
#define DMF_ESC_RET_SSTMASK 0x0000FFFF
|
||||
#define DMF_ESC_RET_IMMMASK 0x7FFF0000
|
||||
|
||||
typedef enum
|
||||
{
|
||||
dmf_escret_generic_ok = 0x00010000,
|
||||
dmf_escret_bad_state = 0x00100000,
|
||||
dmf_escret_access_denied = 0x00200000,
|
||||
dmf_escret_bad_buffer_size = 0x00400000,
|
||||
dmf_escret_internal_err = 0x00800000,
|
||||
dmf_escret_out_of_memory = 0x02000000,
|
||||
dmf_escret_already_connected = 0x04000000,
|
||||
dmf_escret_oh_boy_too_late = 0x08000000,
|
||||
dmf_escret_bad_window = 0x10000000,
|
||||
dmf_escret_drv_ver_higher = 0x20000000,
|
||||
dmf_escret_drv_ver_lower = 0x40000000,
|
||||
} dmf_esc_retcode;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG cbSize;
|
||||
ULONG app_actual_version;
|
||||
ULONG display_minreq_version;
|
||||
ULONG connect_options;
|
||||
} Esc_dmf_Qvi_IN;
|
||||
|
||||
enum
|
||||
{
|
||||
esc_qvi_prod_name_max = 16,
|
||||
};
|
||||
|
||||
#define ESC_QVI_PROD_MIRAGE "MIRAGE"
|
||||
#define ESC_QVI_PROD_QUASAR "QUASAR"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG cbSize;
|
||||
ULONG display_actual_version;
|
||||
ULONG miniport_actual_version;
|
||||
ULONG app_minreq_version;
|
||||
ULONG display_buildno;
|
||||
ULONG miniport_buildno;
|
||||
char prod_name[esc_qvi_prod_name_max];
|
||||
} Esc_dmf_Qvi_OUT;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG cbSize;
|
||||
char* pDstBmBuf;
|
||||
ULONG nDstBmBufSize;
|
||||
} Esc_dmf_pointer_shape_get_IN;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG cbSize;
|
||||
POINTL BmSize;
|
||||
char* pMaskBm;
|
||||
ULONG nMaskBmSize;
|
||||
char* pColorBm;
|
||||
ULONG nColorBmSize;
|
||||
char* pColorBmPal;
|
||||
ULONG nColorBmPalEntries;
|
||||
} Esc_dmf_pointer_shape_get_OUT;
|
||||
|
||||
WINPR_ATTR_NODISCARD BOOL wf_mirror_driver_find_display_device(wfInfo* wfi);
|
||||
WINPR_ATTR_NODISCARD BOOL wf_mirror_driver_display_device_attach(wfInfo* wfi, DWORD mode);
|
||||
WINPR_ATTR_NODISCARD BOOL wf_mirror_driver_update(wfInfo* wfi, int mode);
|
||||
WINPR_ATTR_NODISCARD BOOL wf_mirror_driver_map_memory(wfInfo* wfi);
|
||||
WINPR_ATTR_NODISCARD BOOL wf_mirror_driver_cleanup(wfInfo* wfi);
|
||||
|
||||
WINPR_ATTR_NODISCARD BOOL wf_mirror_driver_activate(wfInfo* wfi);
|
||||
void wf_mirror_driver_deactivate(wfInfo* wfi);
|
||||
|
||||
#endif /* FREERDP_SERVER_WIN_MIRAGE_H */
|
||||
415
third_party/FreeRDP/server/Windows/wf_peer.c
vendored
Normal file
415
third_party/FreeRDP/server/Windows/wf_peer.c
vendored
Normal file
@@ -0,0 +1,415 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Client
|
||||
* FreeRDP Windows Server
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2012 Corey Clayton <can.of.tuna@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 <freerdp/config.h>
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/tchar.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/windows.h>
|
||||
|
||||
#include <freerdp/listener.h>
|
||||
#include <freerdp/codec/rfx.h>
|
||||
#include <freerdp/build-config.h>
|
||||
#include <freerdp/crypto/certificate.h>
|
||||
|
||||
#include "wf_info.h"
|
||||
#include "wf_input.h"
|
||||
#include "wf_mirage.h"
|
||||
#include "wf_update.h"
|
||||
#include "wf_settings.h"
|
||||
#include "wf_rdpsnd.h"
|
||||
|
||||
#include "wf_peer.h"
|
||||
#include <freerdp/peer.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG SERVER_TAG("windows")
|
||||
|
||||
#define SERVER_KEY "Software\\" FREERDP_VENDOR_STRING "\\" FREERDP_PRODUCT_STRING
|
||||
|
||||
static DWORD WINAPI wf_peer_main_loop(LPVOID lpParam);
|
||||
|
||||
static BOOL wf_peer_context_new(freerdp_peer* client, rdpContext* ctx)
|
||||
{
|
||||
wfPeerContext* context = (wfPeerContext*)ctx;
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (!(context->info = wf_info_get_instance()))
|
||||
return FALSE;
|
||||
|
||||
context->vcm = WTSOpenServerA((LPSTR)client->context);
|
||||
|
||||
if (!context->vcm || context->vcm == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
if (!wf_info_peer_register(context->info, context))
|
||||
{
|
||||
WTSCloseServer(context->vcm);
|
||||
context->vcm = nullptr;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void wf_peer_context_free(freerdp_peer* client, rdpContext* ctx)
|
||||
{
|
||||
wfPeerContext* context = (wfPeerContext*)ctx;
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
wf_info_peer_unregister(context->info, context);
|
||||
|
||||
if (context->rdpsnd)
|
||||
{
|
||||
wf_rdpsnd_lock();
|
||||
context->info->snd_stop = TRUE;
|
||||
rdpsnd_server_context_free(context->rdpsnd);
|
||||
wf_rdpsnd_unlock();
|
||||
}
|
||||
|
||||
WTSCloseServer(context->vcm);
|
||||
}
|
||||
|
||||
static BOOL wf_peer_init(freerdp_peer* client)
|
||||
{
|
||||
client->ContextSize = sizeof(wfPeerContext);
|
||||
client->ContextNew = wf_peer_context_new;
|
||||
client->ContextFree = wf_peer_context_free;
|
||||
return freerdp_peer_context_new(client);
|
||||
}
|
||||
|
||||
static BOOL wf_peer_post_connect(freerdp_peer* client)
|
||||
{
|
||||
wfInfo* wfi;
|
||||
rdpSettings* settings;
|
||||
wfPeerContext* context;
|
||||
|
||||
WINPR_ASSERT(client);
|
||||
|
||||
context = (wfPeerContext*)client->context;
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
wfi = context->info;
|
||||
WINPR_ASSERT(wfi);
|
||||
|
||||
settings = client->context->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
if ((get_screen_info(wfi->screenID, nullptr, 0, &wfi->servscreen_width, &wfi->servscreen_height,
|
||||
&wfi->bitsPerPixel) == 0) ||
|
||||
(wfi->servscreen_width == 0) || (wfi->servscreen_height == 0) || (wfi->bitsPerPixel == 0))
|
||||
{
|
||||
WLog_ERR(TAG, "postconnect: error getting screen info for screen %d", wfi->screenID);
|
||||
WLog_ERR(TAG, "\t%dx%dx%d", wfi->servscreen_height, wfi->servscreen_width,
|
||||
wfi->bitsPerPixel);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) != wfi->servscreen_width) ||
|
||||
(freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) != wfi->servscreen_height))
|
||||
{
|
||||
/*
|
||||
WLog_DBG(TAG, "Client requested resolution %"PRIu32"x%"PRIu32", but will resize to %dx%d",
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight), wfi->servscreen_width,
|
||||
wfi->servscreen_height);
|
||||
*/
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, wfi->servscreen_width) ||
|
||||
!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, wfi->servscreen_height) ||
|
||||
!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, wfi->bitsPerPixel))
|
||||
return FALSE;
|
||||
|
||||
WINPR_ASSERT(client->context->update);
|
||||
WINPR_ASSERT(client->context->update->DesktopResize);
|
||||
client->context->update->DesktopResize(client->context);
|
||||
}
|
||||
|
||||
if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, "rdpsnd"))
|
||||
{
|
||||
wf_peer_rdpsnd_init(context); /* Audio Output */
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL wf_peer_activate(freerdp_peer* client)
|
||||
{
|
||||
wfInfo* wfi;
|
||||
wfPeerContext* context = (wfPeerContext*)client->context;
|
||||
wfi = context->info;
|
||||
client->activated = TRUE;
|
||||
wf_update_peer_activate(wfi, context);
|
||||
wfreerdp_server_peer_callback_event(((rdpContext*)context)->peer->pId,
|
||||
FREERDP_SERVER_WIN_SRV_CALLBACK_EVENT_ACTIVATE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL wf_peer_logon(freerdp_peer* client, const SEC_WINNT_AUTH_IDENTITY* identity,
|
||||
BOOL automatic)
|
||||
{
|
||||
wfreerdp_server_peer_callback_event(((rdpContext*)client->context)->peer->pId,
|
||||
FREERDP_SERVER_WIN_SRV_CALLBACK_EVENT_AUTH);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL wf_peer_synchronize_event(rdpInput* input, UINT32 flags)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL wf_peer_accepted(freerdp_listener* instance, freerdp_peer* client)
|
||||
{
|
||||
HANDLE hThread;
|
||||
|
||||
if (!(hThread = CreateThread(nullptr, 0, wf_peer_main_loop, client, 0, nullptr)))
|
||||
return FALSE;
|
||||
|
||||
(void)CloseHandle(hThread);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static DWORD WINAPI wf_peer_socket_listener(LPVOID lpParam)
|
||||
{
|
||||
wfPeerContext* context;
|
||||
freerdp_peer* client = (freerdp_peer*)lpParam;
|
||||
|
||||
WINPR_ASSERT(client);
|
||||
WINPR_ASSERT(client->GetEventHandles);
|
||||
WINPR_ASSERT(client->CheckFileDescriptor);
|
||||
|
||||
context = (wfPeerContext*)client->context;
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
while (1)
|
||||
{
|
||||
DWORD status;
|
||||
HANDLE handles[MAXIMUM_WAIT_OBJECTS] = WINPR_C_ARRAY_INIT;
|
||||
DWORD count = client->GetEventHandles(client, handles, ARRAYSIZE(handles));
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get FreeRDP file descriptor");
|
||||
break;
|
||||
}
|
||||
|
||||
status = WaitForMultipleObjects(count, handles, FALSE, INFINITE);
|
||||
if (status == WAIT_FAILED)
|
||||
{
|
||||
WLog_ERR(TAG, "WaitForMultipleObjects failed");
|
||||
break;
|
||||
}
|
||||
|
||||
(void)SetEvent(context->socketEvent);
|
||||
(void)WaitForSingleObject(context->socketSemaphore, INFINITE);
|
||||
|
||||
if (context->socketClose)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BOOL wf_peer_read_settings(freerdp_peer* client)
|
||||
{
|
||||
rdpSettings* settings;
|
||||
|
||||
WINPR_ASSERT(client);
|
||||
WINPR_ASSERT(client->context);
|
||||
|
||||
settings = client->context->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
char* CertificateFile = nullptr;
|
||||
if (!wf_settings_read_string_ascii(HKEY_LOCAL_MACHINE, SERVER_KEY, _T("CertificateFile"),
|
||||
&(CertificateFile)))
|
||||
CertificateFile = _strdup("server.crt");
|
||||
|
||||
rdpCertificate* cert = freerdp_certificate_new_from_file(CertificateFile);
|
||||
free(CertificateFile);
|
||||
if (!cert)
|
||||
return FALSE;
|
||||
|
||||
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerCertificate, cert, 1))
|
||||
return FALSE;
|
||||
|
||||
char* PrivateKeyFile = nullptr;
|
||||
if (!wf_settings_read_string_ascii(HKEY_LOCAL_MACHINE, SERVER_KEY, _T("PrivateKeyFile"),
|
||||
&(PrivateKeyFile)))
|
||||
PrivateKeyFile = _strdup("server.key");
|
||||
|
||||
rdpPrivateKey* key = freerdp_key_new_from_file_enc(PrivateKeyFile, nullptr);
|
||||
free(PrivateKeyFile);
|
||||
|
||||
if (!key)
|
||||
return FALSE;
|
||||
|
||||
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerRsaKey, key, 1))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DWORD WINAPI wf_peer_main_loop(LPVOID lpParam)
|
||||
{
|
||||
wfInfo* wfi;
|
||||
DWORD nCount;
|
||||
DWORD status;
|
||||
HANDLE handles[32];
|
||||
rdpSettings* settings;
|
||||
wfPeerContext* context;
|
||||
freerdp_peer* client = (freerdp_peer*)lpParam;
|
||||
|
||||
if (!wf_peer_init(client))
|
||||
goto fail_peer_init;
|
||||
|
||||
WINPR_ASSERT(client->context);
|
||||
|
||||
settings = client->context->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE))
|
||||
goto fail_peer_init;
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, 32))
|
||||
goto fail_peer_init;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, FALSE))
|
||||
goto fail_peer_init;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, FALSE))
|
||||
goto fail_peer_init;
|
||||
|
||||
if (!wf_peer_read_settings(client))
|
||||
goto fail_peer_init;
|
||||
|
||||
client->PostConnect = wf_peer_post_connect;
|
||||
client->Activate = wf_peer_activate;
|
||||
client->Logon = wf_peer_logon;
|
||||
|
||||
WINPR_ASSERT(client->context->input);
|
||||
client->context->input->SynchronizeEvent = wf_peer_synchronize_event;
|
||||
client->context->input->KeyboardEvent = wf_peer_keyboard_event;
|
||||
client->context->input->UnicodeKeyboardEvent = wf_peer_unicode_keyboard_event;
|
||||
client->context->input->MouseEvent = wf_peer_mouse_event;
|
||||
client->context->input->ExtendedMouseEvent = wf_peer_extended_mouse_event;
|
||||
|
||||
WINPR_ASSERT(client->Initialize);
|
||||
if (!client->Initialize(client))
|
||||
goto fail_client_initialize;
|
||||
|
||||
context = (wfPeerContext*)client->context;
|
||||
|
||||
if (context->socketClose)
|
||||
goto fail_socked_closed;
|
||||
|
||||
wfi = context->info;
|
||||
|
||||
if (wfi->input_disabled)
|
||||
{
|
||||
WLog_INFO(TAG, "client input is disabled");
|
||||
client->context->input->KeyboardEvent = wf_peer_keyboard_event_dummy;
|
||||
client->context->input->UnicodeKeyboardEvent = wf_peer_unicode_keyboard_event_dummy;
|
||||
client->context->input->MouseEvent = wf_peer_mouse_event_dummy;
|
||||
client->context->input->ExtendedMouseEvent = wf_peer_extended_mouse_event_dummy;
|
||||
}
|
||||
|
||||
if (!(context->socketEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
|
||||
goto fail_socket_event;
|
||||
|
||||
if (!(context->socketSemaphore = CreateSemaphore(nullptr, 0, 1, nullptr)))
|
||||
goto fail_socket_semaphore;
|
||||
|
||||
if (!(context->socketThread =
|
||||
CreateThread(nullptr, 0, wf_peer_socket_listener, client, 0, nullptr)))
|
||||
goto fail_socket_thread;
|
||||
|
||||
WLog_INFO(TAG, "We've got a client %s", client->local ? "(local)" : client->hostname);
|
||||
nCount = 0;
|
||||
handles[nCount++] = context->updateEvent;
|
||||
handles[nCount++] = context->socketEvent;
|
||||
|
||||
while (1)
|
||||
{
|
||||
status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE);
|
||||
|
||||
if ((status == WAIT_FAILED) || (status == WAIT_TIMEOUT))
|
||||
{
|
||||
WLog_ERR(TAG, "WaitForMultipleObjects failed");
|
||||
break;
|
||||
}
|
||||
|
||||
if (WaitForSingleObject(context->updateEvent, 0) == 0)
|
||||
{
|
||||
if (client->activated)
|
||||
wf_update_peer_send(wfi, context);
|
||||
|
||||
(void)ResetEvent(context->updateEvent);
|
||||
ReleaseSemaphore(wfi->updateSemaphore, 1, nullptr);
|
||||
}
|
||||
|
||||
if (WaitForSingleObject(context->socketEvent, 0) == 0)
|
||||
{
|
||||
if (client->CheckFileDescriptor(client) != TRUE)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to check peer file descriptor");
|
||||
context->socketClose = TRUE;
|
||||
}
|
||||
|
||||
(void)ResetEvent(context->socketEvent);
|
||||
ReleaseSemaphore(context->socketSemaphore, 1, nullptr);
|
||||
|
||||
if (context->socketClose)
|
||||
break;
|
||||
}
|
||||
|
||||
// force disconnect
|
||||
if (wfi->force_all_disconnect == TRUE)
|
||||
{
|
||||
WLog_INFO(TAG, "Forcing Disconnect -> ");
|
||||
break;
|
||||
}
|
||||
|
||||
/* FIXME: we should wait on this, instead of calling it every time */
|
||||
if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE)
|
||||
break;
|
||||
}
|
||||
|
||||
WLog_INFO(TAG, "Client %s disconnected.", client->local ? "(local)" : client->hostname);
|
||||
|
||||
if (WaitForSingleObject(context->updateEvent, 0) == 0)
|
||||
{
|
||||
(void)ResetEvent(context->updateEvent);
|
||||
ReleaseSemaphore(wfi->updateSemaphore, 1, nullptr);
|
||||
}
|
||||
|
||||
wf_update_peer_deactivate(wfi, context);
|
||||
client->Disconnect(client);
|
||||
fail_socket_thread:
|
||||
(void)CloseHandle(context->socketSemaphore);
|
||||
context->socketSemaphore = nullptr;
|
||||
fail_socket_semaphore:
|
||||
(void)CloseHandle(context->socketEvent);
|
||||
context->socketEvent = nullptr;
|
||||
fail_socket_event:
|
||||
fail_socked_closed:
|
||||
fail_client_initialize:
|
||||
freerdp_peer_context_free(client);
|
||||
fail_peer_init:
|
||||
freerdp_peer_free(client);
|
||||
return 0;
|
||||
}
|
||||
29
third_party/FreeRDP/server/Windows/wf_peer.h
vendored
Normal file
29
third_party/FreeRDP/server/Windows/wf_peer.h
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Windows Server
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_WIN_PEER_H
|
||||
#define FREERDP_SERVER_WIN_PEER_H
|
||||
|
||||
#include "wf_interface.h"
|
||||
|
||||
#include <freerdp/listener.h>
|
||||
|
||||
WINPR_ATTR_NODISCARD BOOL wf_peer_accepted(freerdp_listener* instance, freerdp_peer* client);
|
||||
|
||||
#endif /* FREERDP_SERVER_WIN_PEER_H */
|
||||
153
third_party/FreeRDP/server/Windows/wf_rdpsnd.c
vendored
Normal file
153
third_party/FreeRDP/server/Windows/wf_rdpsnd.c
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Windows Server (Audio Output)
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2013 Corey Clayton <can.of.tuna@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 <freerdp/config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <winpr/windows.h>
|
||||
#include <freerdp/server/server-common.h>
|
||||
|
||||
#include "wf_rdpsnd.h"
|
||||
#include "wf_info.h"
|
||||
|
||||
#ifdef WITH_RDPSND_DSOUND
|
||||
|
||||
#include "wf_directsound.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "wf_wasapi.h"
|
||||
|
||||
#endif
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG SERVER_TAG("windows")
|
||||
|
||||
static void wf_peer_rdpsnd_activated(RdpsndServerContext* context)
|
||||
{
|
||||
wfInfo* wfi;
|
||||
wfi = wf_info_get_instance();
|
||||
wfi->agreed_format = nullptr;
|
||||
WLog_DBG(TAG, "Client supports the following %d formats:", context->num_client_formats);
|
||||
|
||||
size_t i = 0;
|
||||
for (; i < context->num_client_formats; i++)
|
||||
{
|
||||
// TODO: improve the way we agree on a format
|
||||
for (size_t j = 0; j < context->num_server_formats; j++)
|
||||
{
|
||||
if ((context->client_formats[i].wFormatTag == context->server_formats[j].wFormatTag) &&
|
||||
(context->client_formats[i].nChannels == context->server_formats[j].nChannels) &&
|
||||
(context->client_formats[i].nSamplesPerSec ==
|
||||
context->server_formats[j].nSamplesPerSec))
|
||||
{
|
||||
WLog_DBG(TAG, "agreed on format!");
|
||||
wfi->agreed_format = (AUDIO_FORMAT*)&context->server_formats[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (wfi->agreed_format != nullptr)
|
||||
break;
|
||||
}
|
||||
|
||||
if (wfi->agreed_format == nullptr)
|
||||
{
|
||||
WLog_ERR(TAG, "Could not agree on a audio format with the server");
|
||||
return;
|
||||
}
|
||||
|
||||
context->SelectFormat(context, i);
|
||||
context->SetVolume(context, 0x7FFF, 0x7FFF);
|
||||
#ifdef WITH_RDPSND_DSOUND
|
||||
wf_directsound_activate(context);
|
||||
#else
|
||||
wf_wasapi_activate(context);
|
||||
#endif
|
||||
}
|
||||
|
||||
int wf_rdpsnd_lock()
|
||||
{
|
||||
DWORD dRes;
|
||||
wfInfo* wfi;
|
||||
wfi = wf_info_get_instance();
|
||||
dRes = WaitForSingleObject(wfi->snd_mutex, INFINITE);
|
||||
|
||||
switch (dRes)
|
||||
{
|
||||
case WAIT_ABANDONED:
|
||||
case WAIT_OBJECT_0:
|
||||
return TRUE;
|
||||
break;
|
||||
|
||||
case WAIT_TIMEOUT:
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
case WAIT_FAILED:
|
||||
WLog_ERR(TAG, "wf_rdpsnd_lock failed with 0x%08lX", GetLastError());
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int wf_rdpsnd_unlock()
|
||||
{
|
||||
wfInfo* wfi;
|
||||
wfi = wf_info_get_instance();
|
||||
|
||||
if (ReleaseMutex(wfi->snd_mutex) == 0)
|
||||
{
|
||||
WLog_DBG(TAG, "wf_rdpsnd_unlock failed with 0x%08lX", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL wf_peer_rdpsnd_init(wfPeerContext* context)
|
||||
{
|
||||
wfInfo* wfi = wf_info_get_instance();
|
||||
|
||||
if (!wfi)
|
||||
return FALSE;
|
||||
|
||||
if (!(wfi->snd_mutex = CreateMutex(nullptr, FALSE, nullptr)))
|
||||
return FALSE;
|
||||
|
||||
context->rdpsnd = rdpsnd_server_context_new(context->vcm);
|
||||
context->rdpsnd->rdpcontext = &context->_p;
|
||||
context->rdpsnd->data = context;
|
||||
context->rdpsnd->num_server_formats =
|
||||
server_rdpsnd_get_formats(&context->rdpsnd->server_formats);
|
||||
|
||||
if (context->rdpsnd->num_server_formats > 0)
|
||||
context->rdpsnd->src_format = &context->rdpsnd->server_formats[0];
|
||||
|
||||
context->rdpsnd->Activated = wf_peer_rdpsnd_activated;
|
||||
context->rdpsnd->Initialize(context->rdpsnd, TRUE);
|
||||
wf_rdpsnd_set_latest_peer(context);
|
||||
wfi->snd_stop = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
33
third_party/FreeRDP/server/Windows/wf_rdpsnd.h
vendored
Normal file
33
third_party/FreeRDP/server/Windows/wf_rdpsnd.h
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Windows Server (Audio Output)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_WIN_RDPSND_H
|
||||
#define FREERDP_SERVER_WIN_RDPSND_H
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/listener.h>
|
||||
#include <freerdp/server/rdpsnd.h>
|
||||
|
||||
#include "wf_interface.h"
|
||||
|
||||
WINPR_ATTR_NODISCARD int wf_rdpsnd_lock(void);
|
||||
WINPR_ATTR_NODISCARD int wf_rdpsnd_unlock(void);
|
||||
WINPR_ATTR_NODISCARD BOOL wf_peer_rdpsnd_init(wfPeerContext* context);
|
||||
|
||||
#endif /* FREERDP_SERVER_WIN_RDPSND_H */
|
||||
103
third_party/FreeRDP/server/Windows/wf_settings.c
vendored
Normal file
103
third_party/FreeRDP/server/Windows/wf_settings.c
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Windows Server
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/tchar.h>
|
||||
#include <winpr/windows.h>
|
||||
|
||||
#include "wf_settings.h"
|
||||
|
||||
BOOL wf_settings_read_dword(HKEY key, LPCSTR subkey, LPTSTR name, DWORD* value)
|
||||
{
|
||||
HKEY hKey;
|
||||
LONG status;
|
||||
DWORD dwType;
|
||||
DWORD dwSize;
|
||||
DWORD dwValue;
|
||||
|
||||
status = RegOpenKeyExA(key, subkey, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
|
||||
|
||||
if (status == ERROR_SUCCESS)
|
||||
{
|
||||
dwSize = sizeof(DWORD);
|
||||
|
||||
status = RegQueryValueEx(hKey, name, nullptr, &dwType, (BYTE*)&dwValue, &dwSize);
|
||||
|
||||
if (status == ERROR_SUCCESS)
|
||||
*value = dwValue;
|
||||
|
||||
RegCloseKey(hKey);
|
||||
|
||||
return (status == ERROR_SUCCESS) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL wf_settings_read_string_ascii(HKEY key, LPCSTR subkey, LPTSTR name, char** value)
|
||||
{
|
||||
HKEY hKey;
|
||||
int length;
|
||||
LONG status;
|
||||
DWORD dwType;
|
||||
DWORD dwSize;
|
||||
char* strA;
|
||||
TCHAR* strX = nullptr;
|
||||
|
||||
status = RegOpenKeyExA(key, subkey, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
|
||||
|
||||
if (status != ERROR_SUCCESS)
|
||||
return FALSE;
|
||||
|
||||
status = RegQueryValueEx(hKey, name, nullptr, &dwType, nullptr, &dwSize);
|
||||
|
||||
if (status == ERROR_SUCCESS)
|
||||
{
|
||||
strX = (LPTSTR)malloc(dwSize + sizeof(TCHAR));
|
||||
if (!strX)
|
||||
return FALSE;
|
||||
status = RegQueryValueEx(hKey, name, nullptr, &dwType, (BYTE*)strX, &dwSize);
|
||||
|
||||
if (status != ERROR_SUCCESS)
|
||||
{
|
||||
free(strX);
|
||||
RegCloseKey(hKey);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (strX)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
length =
|
||||
WideCharToMultiByte(CP_UTF8, 0, strX, lstrlenW(strX), nullptr, 0, nullptr, nullptr);
|
||||
strA = (char*)malloc(length + 1);
|
||||
WideCharToMultiByte(CP_UTF8, 0, strX, lstrlenW(strX), strA, length, nullptr, nullptr);
|
||||
strA[length] = '\0';
|
||||
free(strX);
|
||||
#else
|
||||
strA = (char*)strX;
|
||||
#endif
|
||||
*value = strA;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
30
third_party/FreeRDP/server/Windows/wf_settings.h
vendored
Normal file
30
third_party/FreeRDP/server/Windows/wf_settings.h
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Windows Server
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_WIN_SETTINGS_H
|
||||
#define FREERDP_SERVER_WIN_SETTINGS_H
|
||||
|
||||
#include "wf_interface.h"
|
||||
|
||||
WINPR_ATTR_NODISCARD BOOL wf_settings_read_dword(HKEY key, LPCSTR subkey, LPTSTR name,
|
||||
DWORD* value);
|
||||
WINPR_ATTR_NODISCARD BOOL wf_settings_read_string_ascii(HKEY key, LPCSTR subkey, LPTSTR name,
|
||||
char** value);
|
||||
|
||||
#endif /* FREERDP_SERVER_WIN_SETTINGS_H */
|
||||
252
third_party/FreeRDP/server/Windows/wf_update.c
vendored
Normal file
252
third_party/FreeRDP/server/Windows/wf_update.c
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Client
|
||||
* FreeRDP Windows Server
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2012 Corey Clayton <can.of.tuna@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 <freerdp/config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <winpr/windows.h>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/listener.h>
|
||||
|
||||
#include "wf_peer.h"
|
||||
#include "wf_info.h"
|
||||
#include "wf_mirage.h"
|
||||
|
||||
#include "wf_update.h"
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG SERVER_TAG("windows")
|
||||
|
||||
DWORD WINAPI wf_update_thread(LPVOID lpParam)
|
||||
{
|
||||
DWORD fps;
|
||||
wfInfo* wfi;
|
||||
DWORD beg, end;
|
||||
DWORD diff, rate;
|
||||
wfi = (wfInfo*)lpParam;
|
||||
fps = wfi->framesPerSecond;
|
||||
rate = 1000 / fps;
|
||||
|
||||
while (1)
|
||||
{
|
||||
beg = GetTickCount();
|
||||
|
||||
if (wf_info_lock(wfi) > 0)
|
||||
{
|
||||
if (wfi->activePeerCount > 0)
|
||||
{
|
||||
wf_info_update_changes(wfi);
|
||||
|
||||
if (wf_info_have_updates(wfi))
|
||||
{
|
||||
wf_update_encode(wfi);
|
||||
// WLog_DBG(TAG, "Start of parallel sending");
|
||||
int index = 0;
|
||||
|
||||
for (int peerindex = 0; peerindex < wfi->peerCount; peerindex++)
|
||||
{
|
||||
for (; index < FREERDP_SERVER_WIN_INFO_MAXPEERS; index++)
|
||||
{
|
||||
if (wfi->peers[index] && wfi->peers[index]->activated)
|
||||
{
|
||||
// WLog_DBG(TAG, "Setting event for %d of %d", index + 1,
|
||||
// wfi->activePeerCount);
|
||||
(void)SetEvent(
|
||||
((wfPeerContext*)wfi->peers[index]->context)->updateEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int index = 0; index < wfi->activePeerCount; index++)
|
||||
{
|
||||
// WLog_DBG(TAG, "Waiting for %d of %d", index + 1, wfi->activePeerCount);
|
||||
// WaitForSingleObject(wfi->updateSemaphore, INFINITE);
|
||||
(void)WaitForSingleObject(wfi->updateSemaphore, 1000);
|
||||
}
|
||||
|
||||
// WLog_DBG(TAG, "End of parallel sending");
|
||||
wf_info_clear_invalid_region(wfi);
|
||||
}
|
||||
}
|
||||
|
||||
wf_info_unlock(wfi);
|
||||
}
|
||||
|
||||
end = GetTickCount();
|
||||
diff = end - beg;
|
||||
|
||||
if (diff < rate)
|
||||
{
|
||||
Sleep(rate - diff);
|
||||
}
|
||||
}
|
||||
|
||||
// WLog_DBG(TAG, "Exiting Update Thread");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wf_update_encode(wfInfo* wfi)
|
||||
{
|
||||
RFX_RECT rect;
|
||||
long height, width;
|
||||
BYTE* pDataBits = nullptr;
|
||||
int stride;
|
||||
SURFACE_BITS_COMMAND* cmd;
|
||||
wf_info_find_invalid_region(wfi);
|
||||
cmd = &wfi->cmd;
|
||||
Stream_ResetPosition(wfi->s);
|
||||
wf_info_getScreenData(wfi, &width, &height, &pDataBits, &stride);
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.width = (UINT16)width;
|
||||
rect.height = (UINT16)height;
|
||||
// WLog_DBG(TAG, "x:%"PRId32" y:%"PRId32" w:%ld h:%ld", wfi->invalid.left, wfi->invalid.top,
|
||||
// width, height);
|
||||
Stream_Clear(wfi->s);
|
||||
|
||||
if (!(rfx_compose_message(wfi->rfx_context, wfi->s, &rect, 1, pDataBits, width, height,
|
||||
stride)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
wfi->frame_idx = rfx_context_get_frame_idx(wfi->rfx_context);
|
||||
cmd->destLeft = wfi->invalid.left;
|
||||
cmd->destTop = wfi->invalid.top;
|
||||
cmd->destRight = wfi->invalid.left + width;
|
||||
cmd->destBottom = wfi->invalid.top + height;
|
||||
cmd->bmp.bpp = 32;
|
||||
cmd->bmp.codecID = 3;
|
||||
cmd->bmp.width = width;
|
||||
cmd->bmp.height = height;
|
||||
cmd->bmp.bitmapDataLength = Stream_GetPosition(wfi->s);
|
||||
cmd->bmp.bitmapData = Stream_Buffer(wfi->s);
|
||||
}
|
||||
|
||||
void wf_update_peer_send(wfInfo* wfi, wfPeerContext* context)
|
||||
{
|
||||
freerdp_peer* client;
|
||||
|
||||
WINPR_ASSERT(wfi);
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
client = ((rdpContext*)context)->peer;
|
||||
WINPR_ASSERT(client);
|
||||
|
||||
/* This happens when the RemoteFX encoder state is reset */
|
||||
|
||||
if (wfi->frame_idx == 1)
|
||||
context->frame_idx = 0;
|
||||
|
||||
/*
|
||||
* When a new client connects, it is possible that old frames from
|
||||
* from a previous encoding state remain. Those frames should be discarded
|
||||
* as they will cause an error condition in mstsc.
|
||||
*/
|
||||
|
||||
if ((context->frame_idx + 1) != wfi->frame_idx)
|
||||
{
|
||||
/* This frame is meant to be discarded */
|
||||
if (context->frame_idx == 0)
|
||||
return;
|
||||
|
||||
/* This is an unexpected error condition */
|
||||
WLog_DBG(TAG, "Unexpected Frame Index: Actual: %d Expected: %d", wfi->frame_idx,
|
||||
context->frame_idx + 1);
|
||||
}
|
||||
|
||||
WINPR_ASSERT(client->context);
|
||||
WINPR_ASSERT(client->context->settings);
|
||||
WINPR_ASSERT(client->context->update);
|
||||
WINPR_ASSERT(client->context->update->SurfaceBits);
|
||||
|
||||
wfi->cmd.bmp.codecID =
|
||||
freerdp_settings_get_uint32(client->context->settings, FreeRDP_RemoteFxCodecId);
|
||||
client->context->update->SurfaceBits(client->context, &wfi->cmd);
|
||||
context->frame_idx++;
|
||||
}
|
||||
|
||||
void wf_update_encoder_reset(wfInfo* wfi)
|
||||
{
|
||||
if (wf_info_lock(wfi) > 0)
|
||||
{
|
||||
WLog_DBG(TAG, "Resetting encoder");
|
||||
|
||||
if (wfi->rfx_context)
|
||||
{
|
||||
rfx_context_reset(wfi->rfx_context, wfi->servscreen_width, wfi->servscreen_height);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: pass ThreadingFlags somehow */
|
||||
wfi->rfx_context = rfx_context_new(TRUE);
|
||||
rfx_context_set_mode(wfi->rfx_context, RLGR3);
|
||||
rfx_context_reset(wfi->rfx_context, wfi->servscreen_width, wfi->servscreen_height);
|
||||
rfx_context_set_pixel_format(wfi->rfx_context, PIXEL_FORMAT_BGRA32);
|
||||
wfi->s = Stream_New(nullptr, 0xFFFF);
|
||||
}
|
||||
|
||||
wf_info_invalidate_full_screen(wfi);
|
||||
wf_info_unlock(wfi);
|
||||
}
|
||||
}
|
||||
|
||||
void wf_update_peer_activate(wfInfo* wfi, wfPeerContext* context)
|
||||
{
|
||||
if (wf_info_lock(wfi) > 0)
|
||||
{
|
||||
if (wfi->activePeerCount < 1)
|
||||
{
|
||||
#ifndef WITH_DXGI_1_2
|
||||
wf_mirror_driver_activate(wfi);
|
||||
#endif
|
||||
ResumeThread(wfi->updateThread);
|
||||
}
|
||||
|
||||
wf_update_encoder_reset(wfi);
|
||||
wfi->activePeerCount++;
|
||||
WLog_DBG(TAG, "Activating Peer Updates: %d", wfi->activePeerCount);
|
||||
wf_info_unlock(wfi);
|
||||
}
|
||||
}
|
||||
|
||||
void wf_update_peer_deactivate(wfInfo* wfi, wfPeerContext* context)
|
||||
{
|
||||
if (wf_info_lock(wfi) > 0)
|
||||
{
|
||||
freerdp_peer* client = ((rdpContext*)context)->peer;
|
||||
|
||||
if (client->activated)
|
||||
{
|
||||
if (wfi->activePeerCount <= 1)
|
||||
{
|
||||
wf_mirror_driver_deactivate(wfi);
|
||||
}
|
||||
|
||||
client->activated = FALSE;
|
||||
wfi->activePeerCount--;
|
||||
WLog_DBG(TAG, "Deactivating Peer Updates: %d", wfi->activePeerCount);
|
||||
}
|
||||
|
||||
wf_info_unlock(wfi);
|
||||
}
|
||||
}
|
||||
37
third_party/FreeRDP/server/Windows/wf_update.h
vendored
Normal file
37
third_party/FreeRDP/server/Windows/wf_update.h
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Windows Server
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_WIN_UPDATE_H
|
||||
#define FREERDP_SERVER_WIN_UPDATE_H
|
||||
|
||||
#include "wf_interface.h"
|
||||
|
||||
void wf_update_encode(wfInfo* wfi);
|
||||
void wf_update_send(wfInfo* wfi);
|
||||
|
||||
WINPR_ATTR_NODISCARD DWORD WINAPI wf_update_thread(LPVOID lpParam);
|
||||
|
||||
void wf_update_begin(wfInfo* wfi);
|
||||
void wf_update_peer_send(wfInfo* wfi, wfPeerContext* context);
|
||||
void wf_update_end(wfInfo* wfi);
|
||||
|
||||
void wf_update_peer_activate(wfInfo* wfi, wfPeerContext* context);
|
||||
void wf_update_peer_deactivate(wfInfo* wfi, wfPeerContext* context);
|
||||
|
||||
#endif /* FREERDP_SERVER_WIN_UPDATE_H */
|
||||
333
third_party/FreeRDP/server/Windows/wf_wasapi.c
vendored
Normal file
333
third_party/FreeRDP/server/Windows/wf_wasapi.c
vendored
Normal file
@@ -0,0 +1,333 @@
|
||||
|
||||
#include "wf_wasapi.h"
|
||||
#include "wf_info.h"
|
||||
|
||||
#include <initguid.h>
|
||||
#include <mmdeviceapi.h>
|
||||
#include <functiondiscoverykeys_devpkey.h>
|
||||
#include <audioclient.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG SERVER_TAG("windows")
|
||||
|
||||
//#define REFTIMES_PER_SEC 10000000
|
||||
//#define REFTIMES_PER_MILLISEC 10000
|
||||
|
||||
#define REFTIMES_PER_SEC 100000
|
||||
#define REFTIMES_PER_MILLISEC 100
|
||||
|
||||
//#define REFTIMES_PER_SEC 50000
|
||||
//#define REFTIMES_PER_MILLISEC 50
|
||||
|
||||
#ifndef __MINGW32__
|
||||
DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xBCDE0395, 0xE52F, 0x467C, 0x8E, 0x3D, 0xC4, 0x57, 0x92,
|
||||
0x91, 0x69, 0x2E);
|
||||
DEFINE_GUID(IID_IMMDeviceEnumerator, 0xA95664D2, 0x9614, 0x4F35, 0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36,
|
||||
0x17, 0xE6);
|
||||
DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03,
|
||||
0xb2);
|
||||
DEFINE_GUID(IID_IAudioCaptureClient, 0xc8adbd64, 0xe71e, 0x48a0, 0xa4, 0xde, 0x18, 0x5c, 0x39, 0x5c,
|
||||
0xd3, 0x17);
|
||||
#endif
|
||||
|
||||
LPWSTR devStr = nullptr;
|
||||
wfPeerContext* latestPeer = nullptr;
|
||||
|
||||
int wf_rdpsnd_set_latest_peer(wfPeerContext* peer)
|
||||
{
|
||||
latestPeer = peer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wf_wasapi_activate(RdpsndServerContext* context)
|
||||
{
|
||||
wchar_t* pattern = L"Stereo Mix";
|
||||
HANDLE hThread;
|
||||
|
||||
wf_wasapi_get_device_string(pattern, &devStr);
|
||||
|
||||
if (devStr == nullptr)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to match for output device! Disabling rdpsnd.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
WLog_DBG(TAG, "RDPSND (WASAPI) Activated");
|
||||
if (!(hThread = CreateThread(nullptr, 0, wf_rdpsnd_wasapi_thread, latestPeer, 0, nullptr)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed");
|
||||
return 1;
|
||||
}
|
||||
(void)CloseHandle(hThread);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wf_wasapi_get_device_string(LPWSTR pattern, LPWSTR* deviceStr)
|
||||
{
|
||||
HRESULT hr;
|
||||
IMMDeviceEnumerator* pEnumerator = nullptr;
|
||||
IMMDeviceCollection* pCollection = nullptr;
|
||||
IMMDevice* pEndpoint = nullptr;
|
||||
IPropertyStore* pProps = nullptr;
|
||||
LPWSTR pwszID = nullptr;
|
||||
unsigned int count;
|
||||
|
||||
CoInitialize(nullptr);
|
||||
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, &IID_IMMDeviceEnumerator,
|
||||
(void**)&pEnumerator);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to cocreate device enumerator");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hr = pEnumerator->lpVtbl->EnumAudioEndpoints(pEnumerator, eCapture, DEVICE_STATE_ACTIVE,
|
||||
&pCollection);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to create endpoint collection");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pCollection->lpVtbl->GetCount(pCollection, &count);
|
||||
WLog_INFO(TAG, "Num endpoints: %u", count);
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
WLog_ERR(TAG, "No endpoints!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
PROPVARIANT nameVar;
|
||||
PropVariantInit(&nameVar);
|
||||
|
||||
hr = pCollection->lpVtbl->Item(pCollection, i, &pEndpoint);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get endpoint %u", i);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hr = pEndpoint->lpVtbl->GetId(pEndpoint, &pwszID);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get endpoint ID");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hr = pEndpoint->lpVtbl->OpenPropertyStore(pEndpoint, STGM_READ, &pProps);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to open property store");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hr = pProps->lpVtbl->GetValue(pProps, &PKEY_Device_FriendlyName, &nameVar);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get device friendly name");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// do this a more reliable way
|
||||
if (wcscmp(pattern, nameVar.pwszVal) < 0)
|
||||
{
|
||||
unsigned int devStrLen;
|
||||
WLog_INFO(TAG, "Using sound output endpoint: [%s] (%s)", nameVar.pwszVal, pwszID);
|
||||
// WLog_INFO(TAG, "matched %d characters", wcscmp(pattern, nameVar.pwszVal);
|
||||
devStrLen = wcslen(pwszID);
|
||||
*deviceStr = (LPWSTR)calloc(devStrLen + 1, 2);
|
||||
if (!deviceStr)
|
||||
return -1;
|
||||
wcscpy_s(*deviceStr, devStrLen + 1, pwszID);
|
||||
}
|
||||
CoTaskMemFree(pwszID);
|
||||
pwszID = nullptr;
|
||||
PropVariantClear(&nameVar);
|
||||
|
||||
pProps->lpVtbl->Release(pProps);
|
||||
pProps = nullptr;
|
||||
|
||||
pEndpoint->lpVtbl->Release(pEndpoint);
|
||||
pEndpoint = nullptr;
|
||||
}
|
||||
|
||||
pCollection->lpVtbl->Release(pCollection);
|
||||
pCollection = nullptr;
|
||||
|
||||
pEnumerator->lpVtbl->Release(pEnumerator);
|
||||
pEnumerator = nullptr;
|
||||
CoUninitialize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD WINAPI wf_rdpsnd_wasapi_thread(LPVOID lpParam)
|
||||
{
|
||||
IMMDeviceEnumerator* pEnumerator = nullptr;
|
||||
IMMDevice* pDevice = nullptr;
|
||||
IAudioClient* pAudioClient = nullptr;
|
||||
IAudioCaptureClient* pCaptureClient = nullptr;
|
||||
WAVEFORMATEX* pwfx = nullptr;
|
||||
HRESULT hr;
|
||||
REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;
|
||||
REFERENCE_TIME hnsActualDuration;
|
||||
UINT32 bufferFrameCount;
|
||||
UINT32 numFramesAvailable;
|
||||
UINT32 packetLength = 0;
|
||||
UINT32 dCount = 0;
|
||||
BYTE* pData;
|
||||
|
||||
wfPeerContext* context;
|
||||
wfInfo* wfi;
|
||||
|
||||
wfi = wf_info_get_instance();
|
||||
context = (wfPeerContext*)lpParam;
|
||||
|
||||
CoInitialize(nullptr);
|
||||
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, &IID_IMMDeviceEnumerator,
|
||||
(void**)&pEnumerator);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to cocreate device enumerator");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hr = pEnumerator->lpVtbl->GetDevice(pEnumerator, devStr, &pDevice);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to cocreate get device");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hr = pDevice->lpVtbl->Activate(pDevice, &IID_IAudioClient, CLSCTX_ALL, nullptr,
|
||||
(void**)&pAudioClient);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to activate audio client");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hr = pAudioClient->lpVtbl->GetMixFormat(pAudioClient, &pwfx);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get mix format");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pwfx->wFormatTag = wfi->agreed_format->wFormatTag;
|
||||
pwfx->nChannels = wfi->agreed_format->nChannels;
|
||||
pwfx->nSamplesPerSec = wfi->agreed_format->nSamplesPerSec;
|
||||
pwfx->nAvgBytesPerSec = wfi->agreed_format->nAvgBytesPerSec;
|
||||
pwfx->nBlockAlign = wfi->agreed_format->nBlockAlign;
|
||||
pwfx->wBitsPerSample = wfi->agreed_format->wBitsPerSample;
|
||||
pwfx->cbSize = wfi->agreed_format->cbSize;
|
||||
|
||||
hr = pAudioClient->lpVtbl->Initialize(pAudioClient, AUDCLNT_SHAREMODE_SHARED, 0,
|
||||
hnsRequestedDuration, 0, pwfx, nullptr);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to initialize the audio client");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hr = pAudioClient->lpVtbl->GetBufferSize(pAudioClient, &bufferFrameCount);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get buffer size");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hr = pAudioClient->lpVtbl->GetService(pAudioClient, &IID_IAudioCaptureClient,
|
||||
(void**)&pCaptureClient);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get the capture client");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hnsActualDuration = (UINT32)REFTIMES_PER_SEC * bufferFrameCount / pwfx->nSamplesPerSec;
|
||||
|
||||
hr = pAudioClient->lpVtbl->Start(pAudioClient);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to start capture");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
dCount = 0;
|
||||
|
||||
while (wfi->snd_stop == FALSE)
|
||||
{
|
||||
DWORD flags;
|
||||
|
||||
Sleep(hnsActualDuration / REFTIMES_PER_MILLISEC / 2);
|
||||
|
||||
hr = pCaptureClient->lpVtbl->GetNextPacketSize(pCaptureClient, &packetLength);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get packet length");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while (packetLength != 0)
|
||||
{
|
||||
hr = pCaptureClient->lpVtbl->GetBuffer(pCaptureClient, &pData, &numFramesAvailable,
|
||||
&flags, nullptr, nullptr);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get buffer");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Here we are writing the audio data
|
||||
// not sure if this flag is ever set by the system; msdn is not clear about it
|
||||
if (!(flags & AUDCLNT_BUFFERFLAGS_SILENT))
|
||||
context->rdpsnd->SendSamples(context->rdpsnd, pData, packetLength,
|
||||
(UINT16)(GetTickCount() & 0xffff));
|
||||
|
||||
hr = pCaptureClient->lpVtbl->ReleaseBuffer(pCaptureClient, numFramesAvailable);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to release buffer");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hr = pCaptureClient->lpVtbl->GetNextPacketSize(pCaptureClient, &packetLength);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get packet length");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pAudioClient->lpVtbl->Stop(pAudioClient);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to stop audio client");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
CoTaskMemFree(pwfx);
|
||||
|
||||
if (pEnumerator != nullptr)
|
||||
pEnumerator->lpVtbl->Release(pEnumerator);
|
||||
|
||||
if (pDevice != nullptr)
|
||||
pDevice->lpVtbl->Release(pDevice);
|
||||
|
||||
if (pAudioClient != nullptr)
|
||||
pAudioClient->lpVtbl->Release(pAudioClient);
|
||||
|
||||
if (pCaptureClient != nullptr)
|
||||
pCaptureClient->lpVtbl->Release(pCaptureClient);
|
||||
|
||||
CoUninitialize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
15
third_party/FreeRDP/server/Windows/wf_wasapi.h
vendored
Normal file
15
third_party/FreeRDP/server/Windows/wf_wasapi.h
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef FREERDP_SERVER_WIN_WASAPI_H
|
||||
#define FREERDP_SERVER_WIN_WASAPI_H
|
||||
|
||||
#include <freerdp/server/rdpsnd.h>
|
||||
#include "wf_interface.h"
|
||||
|
||||
WINPR_ATTR_NODISCARD int wf_rdpsnd_set_latest_peer(wfPeerContext* peer);
|
||||
|
||||
WINPR_ATTR_NODISCARD int wf_wasapi_activate(RdpsndServerContext* context);
|
||||
|
||||
WINPR_ATTR_NODISCARD int wf_wasapi_get_device_string(LPWSTR pattern, LPWSTR* deviceStr);
|
||||
|
||||
WINPR_ATTR_NODISCARD DWORD WINAPI wf_rdpsnd_wasapi_thread(LPVOID lpParam);
|
||||
|
||||
#endif /* FREERDP_SERVER_WIN_WASAPI_H */
|
||||
Reference in New Issue
Block a user