Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
80
third_party/FreeRDP/server/Mac/CMakeLists.txt
vendored
Normal file
80
third_party/FreeRDP/server/Mac/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP Mac OS X 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 "mfreerdp-server")
|
||||
set(MODULE_PREFIX "FREERDP_SERVER_MAC")
|
||||
|
||||
include(WarnUnmaintained)
|
||||
warn_unmaintained(${MODULE_NAME} "-DWITH_PLATFORM_SERVER=OFF")
|
||||
|
||||
find_library(AUDIO_TOOL AudioToolbox)
|
||||
find_library(CORE_AUDIO CoreAudio)
|
||||
find_library(CORE_VIDEO CoreVideo)
|
||||
find_library(APP_SERVICES ApplicationServices)
|
||||
find_library(IOKIT IOKit)
|
||||
find_library(IOSURFACE IOSurface)
|
||||
find_library(CARBON Carbon)
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
mfreerdp.c
|
||||
mfreerdp.h
|
||||
mf_interface.c
|
||||
mf_interface.h
|
||||
mf_event.c
|
||||
mf_event.h
|
||||
mf_peer.c
|
||||
mf_peer.h
|
||||
mf_info.c
|
||||
mf_info.h
|
||||
mf_input.c
|
||||
mf_input.h
|
||||
mf_mountain_lion.c
|
||||
mf_mountain_lion.h
|
||||
)
|
||||
|
||||
if(CHANNEL_AUDIN_SERVER)
|
||||
set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} mf_audin.c mf_audin.h)
|
||||
endif()
|
||||
|
||||
if(CHANNEL_RDPSND_SERVER)
|
||||
set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} mf_rdpsnd.c mf_rdpsnd.h)
|
||||
|
||||
endif()
|
||||
|
||||
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
||||
if(WITH_BINARY_VERSIONING)
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME "${MODULE_NAME}${FREERDP_API_VERSION}")
|
||||
endif()
|
||||
|
||||
set(${MODULE_PREFIX}_LIBS
|
||||
${${MODULE_PREFIX}_LIBS}
|
||||
freerdp-server
|
||||
${AUDIO_TOOL}
|
||||
${CORE_AUDIO}
|
||||
${CORE_VIDEO}
|
||||
${APP_SERVICES}
|
||||
${IOKIT}
|
||||
${IOSURFACE}
|
||||
${CARBON}
|
||||
)
|
||||
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Server/Mac")
|
||||
3
third_party/FreeRDP/server/Mac/ModuleOptions.cmake
vendored
Normal file
3
third_party/FreeRDP/server/Mac/ModuleOptions.cmake
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
set(FREERDP_SERVER_NAME "mfreerdp-server")
|
||||
set(FREERDP_SERVER_PLATFORM "X11")
|
||||
set(FREERDP_SERVER_VENDOR "FreeRDP")
|
||||
65
third_party/FreeRDP/server/Mac/mf_audin.c
vendored
Normal file
65
third_party/FreeRDP/server/Mac/mf_audin.c
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Mac OS X Server (Audio Input)
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||
* Copyright 2023 Pascal Nowack <Pascal.Nowack@gmx.de>
|
||||
*
|
||||
* 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 "mfreerdp.h"
|
||||
|
||||
#include "mf_audin.h"
|
||||
#include "mf_interface.h"
|
||||
|
||||
#include <freerdp/server/server-common.h>
|
||||
#include <freerdp/log.h>
|
||||
#define TAG SERVER_TAG("mac")
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static UINT mf_peer_audin_data(audin_server_context* audin, const SNDIN_DATA* data)
|
||||
{
|
||||
/* TODO: Implement */
|
||||
WINPR_ASSERT(audin);
|
||||
WINPR_ASSERT(data);
|
||||
|
||||
WLog_WARN(TAG, "not implemented");
|
||||
WLog_DBG(TAG, "receive %" PRIdz " bytes.", Stream_Length(data->Data));
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
BOOL mf_peer_audin_init(mfPeerContext* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
context->audin = audin_server_context_new(context->vcm);
|
||||
context->audin->rdpcontext = &context->_p;
|
||||
context->audin->userdata = context;
|
||||
|
||||
context->audin->Data = mf_peer_audin_data;
|
||||
|
||||
return audin_server_set_formats(context->audin, -1, nullptr);
|
||||
}
|
||||
|
||||
void mf_peer_audin_uninit(mfPeerContext* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
audin_server_context_free(context->audin);
|
||||
context->audin = nullptr;
|
||||
}
|
||||
33
third_party/FreeRDP/server/Mac/mf_audin.h
vendored
Normal file
33
third_party/FreeRDP/server/Mac/mf_audin.h
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Mac OS X Server (Audio Input)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_MAC_AUDIN_H
|
||||
#define FREERDP_SERVER_MAC_AUDIN_H
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/listener.h>
|
||||
|
||||
#include "mf_types.h"
|
||||
#include "mfreerdp.h"
|
||||
|
||||
WINPR_ATTR_NODISCARD BOOL mf_peer_audin_init(mfPeerContext* context);
|
||||
void mf_peer_audin_uninit(mfPeerContext* context);
|
||||
|
||||
#endif /* FREERDP_SERVER_MAC_AUDIN_H */
|
||||
220
third_party/FreeRDP/server/Mac/mf_event.c
vendored
Normal file
220
third_party/FreeRDP/server/Mac/mf_event.c
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* OS X Server Event Handling
|
||||
*
|
||||
* 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 <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mf_event.h"
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG SERVER_TAG("mac")
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static int mf_is_event_set(mfEventQueue* event_queue)
|
||||
{
|
||||
fd_set rfds;
|
||||
int num_set;
|
||||
struct timeval time = WINPR_C_ARRAY_INIT;
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(event_queue->pipe_fd[0], &rfds);
|
||||
num_set = select(event_queue->pipe_fd[0] + 1, &rfds, 0, 0, &time);
|
||||
|
||||
return (num_set == 1);
|
||||
}
|
||||
|
||||
static void mf_signal_event(mfEventQueue* event_queue)
|
||||
{
|
||||
int length;
|
||||
|
||||
length = write(event_queue->pipe_fd[1], "sig", 4);
|
||||
|
||||
if (length != 4)
|
||||
WLog_ERR(TAG, "mf_signal_event: error");
|
||||
}
|
||||
|
||||
static void mf_set_event(mfEventQueue* event_queue)
|
||||
{
|
||||
int length;
|
||||
|
||||
length = write(event_queue->pipe_fd[1], "sig", 4);
|
||||
|
||||
if (length != 4)
|
||||
WLog_ERR(TAG, "mf_set_event: error");
|
||||
}
|
||||
|
||||
static void mf_clear_events(mfEventQueue* event_queue)
|
||||
{
|
||||
int length;
|
||||
|
||||
while (mf_is_event_set(event_queue))
|
||||
{
|
||||
length = read(event_queue->pipe_fd[0], &length, 4);
|
||||
|
||||
if (length != 4)
|
||||
WLog_ERR(TAG, "mf_clear_event: error");
|
||||
}
|
||||
}
|
||||
|
||||
static void mf_clear_event(mfEventQueue* event_queue)
|
||||
{
|
||||
int length;
|
||||
|
||||
length = read(event_queue->pipe_fd[0], &length, 4);
|
||||
|
||||
if (length != 4)
|
||||
WLog_ERR(TAG, "mf_clear_event: error");
|
||||
}
|
||||
|
||||
void mf_event_push(mfEventQueue* event_queue, mfEvent* event)
|
||||
{
|
||||
pthread_mutex_lock(&(event_queue->mutex));
|
||||
|
||||
if (event_queue->count >= event_queue->size)
|
||||
{
|
||||
event_queue->size *= 2;
|
||||
event_queue->events =
|
||||
(mfEvent**)realloc((void*)event_queue->events, sizeof(mfEvent*) * event_queue->size);
|
||||
}
|
||||
|
||||
event_queue->events[(event_queue->count)++] = event;
|
||||
|
||||
pthread_mutex_unlock(&(event_queue->mutex));
|
||||
|
||||
mf_set_event(event_queue);
|
||||
}
|
||||
|
||||
mfEvent* mf_event_peek(mfEventQueue* event_queue)
|
||||
{
|
||||
mfEvent* event;
|
||||
|
||||
pthread_mutex_lock(&(event_queue->mutex));
|
||||
|
||||
if (event_queue->count < 1)
|
||||
event = nullptr;
|
||||
else
|
||||
event = event_queue->events[0];
|
||||
|
||||
pthread_mutex_unlock(&(event_queue->mutex));
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
mfEvent* mf_event_pop(mfEventQueue* event_queue)
|
||||
{
|
||||
mfEvent* event;
|
||||
|
||||
pthread_mutex_lock(&(event_queue->mutex));
|
||||
|
||||
if (event_queue->count < 1)
|
||||
return nullptr;
|
||||
|
||||
/* remove event signal */
|
||||
mf_clear_event(event_queue);
|
||||
|
||||
event = event_queue->events[0];
|
||||
(event_queue->count)--;
|
||||
|
||||
memmove(&event_queue->events[0], &event_queue->events[1], event_queue->count * sizeof(void*));
|
||||
|
||||
pthread_mutex_unlock(&(event_queue->mutex));
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
mfEventRegion* mf_event_region_new(int x, int y, int width, int height)
|
||||
{
|
||||
mfEventRegion* event_region = malloc(sizeof(mfEventRegion));
|
||||
|
||||
if (event_region != nullptr)
|
||||
{
|
||||
event_region->x = x;
|
||||
event_region->y = y;
|
||||
event_region->width = width;
|
||||
event_region->height = height;
|
||||
}
|
||||
|
||||
return event_region;
|
||||
}
|
||||
|
||||
void mf_event_region_free(mfEventRegion* event_region)
|
||||
{
|
||||
free(event_region);
|
||||
}
|
||||
|
||||
mfEvent* mf_event_new(int type)
|
||||
{
|
||||
mfEvent* event = malloc(sizeof(mfEvent));
|
||||
if (!event)
|
||||
return nullptr;
|
||||
event->type = type;
|
||||
return event;
|
||||
}
|
||||
|
||||
void mf_event_free(mfEvent* event)
|
||||
{
|
||||
free(event);
|
||||
}
|
||||
|
||||
mfEventQueue* mf_event_queue_new()
|
||||
{
|
||||
mfEventQueue* event_queue = malloc(sizeof(mfEventQueue));
|
||||
|
||||
if (event_queue != nullptr)
|
||||
{
|
||||
event_queue->pipe_fd[0] = -1;
|
||||
event_queue->pipe_fd[1] = -1;
|
||||
|
||||
event_queue->size = 16;
|
||||
event_queue->count = 0;
|
||||
event_queue->events = (mfEvent**)malloc(sizeof(mfEvent*) * event_queue->size);
|
||||
|
||||
if (pipe(event_queue->pipe_fd) < 0)
|
||||
{
|
||||
free(event_queue);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
pthread_mutex_init(&(event_queue->mutex), nullptr);
|
||||
}
|
||||
|
||||
return event_queue;
|
||||
}
|
||||
|
||||
void mf_event_queue_free(mfEventQueue* event_queue)
|
||||
{
|
||||
if (event_queue->pipe_fd[0] != -1)
|
||||
{
|
||||
close(event_queue->pipe_fd[0]);
|
||||
event_queue->pipe_fd[0] = -1;
|
||||
}
|
||||
|
||||
if (event_queue->pipe_fd[1] != -1)
|
||||
{
|
||||
close(event_queue->pipe_fd[1]);
|
||||
event_queue->pipe_fd[1] = -1;
|
||||
}
|
||||
|
||||
pthread_mutex_destroy(&(event_queue->mutex));
|
||||
}
|
||||
81
third_party/FreeRDP/server/Mac/mf_event.h
vendored
Normal file
81
third_party/FreeRDP/server/Mac/mf_event.h
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* OS X Server Event Handling
|
||||
*
|
||||
* 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_MAC_EVENT_H
|
||||
#define FREERDP_SERVER_MAC_EVENT_H
|
||||
|
||||
typedef struct mf_event mfEvent;
|
||||
typedef struct mf_event_queue mfEventQueue;
|
||||
typedef struct mf_event_region mfEventRegion;
|
||||
|
||||
#include <pthread.h>
|
||||
#include "mfreerdp.h"
|
||||
|
||||
//#include "mf_peer.h"
|
||||
|
||||
enum mf_event_type
|
||||
{
|
||||
FREERDP_SERVER_MAC_EVENT_TYPE_REGION,
|
||||
FREERDP_SERVER_MAC_EVENT_TYPE_FRAME_TICK
|
||||
};
|
||||
|
||||
struct mf_event
|
||||
{
|
||||
int type;
|
||||
};
|
||||
|
||||
struct mf_event_queue
|
||||
{
|
||||
int size;
|
||||
int count;
|
||||
int pipe_fd[2];
|
||||
mfEvent** events;
|
||||
pthread_mutex_t mutex;
|
||||
};
|
||||
|
||||
struct mf_event_region
|
||||
{
|
||||
int type;
|
||||
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
void mf_event_push(mfEventQueue* event_queue, mfEvent* event);
|
||||
WINPR_ATTR_NODISCARD mfEvent* mf_event_peek(mfEventQueue* event_queue);
|
||||
WINPR_ATTR_NODISCARD mfEvent* mf_event_pop(mfEventQueue* event_queue);
|
||||
|
||||
void mf_event_region_free(mfEventRegion* event_region);
|
||||
|
||||
WINPR_ATTR_MALLOC(mf_event_region_free, 1)
|
||||
WINPR_ATTR_NODISCARD mfEventRegion* mf_event_region_new(int x, int y, int width, int height);
|
||||
|
||||
void mf_event_free(mfEvent* event);
|
||||
|
||||
WINPR_ATTR_MALLOC(mf_event_free, 1)
|
||||
WINPR_ATTR_NODISCARD mfEvent* mf_event_new(int type);
|
||||
|
||||
void mf_event_queue_free(mfEventQueue* event_queue);
|
||||
|
||||
WINPR_ATTR_MALLOC(mf_event_queue_free, 1)
|
||||
WINPR_ATTR_NODISCARD mfEventQueue* mf_event_queue_new(void);
|
||||
|
||||
#endif /* FREERDP_SERVER_MAC_EVENT_H */
|
||||
230
third_party/FreeRDP/server/Mac/mf_info.c
vendored
Normal file
230
third_party/FreeRDP/server/Mac/mf_info.c
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Client
|
||||
* FreeRDP Mac OS X 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 <errno.h>
|
||||
|
||||
#include "mf_info.h"
|
||||
#include "mf_mountain_lion.h"
|
||||
|
||||
#define MF_INFO_DEFAULT_FPS 30
|
||||
#define MF_INFO_MAXPEERS 32
|
||||
|
||||
static mfInfo* mfInfoInstance = nullptr;
|
||||
|
||||
int mf_info_lock(mfInfo* mfi)
|
||||
{
|
||||
int status = pthread_mutex_lock(&mfi->mutex);
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case 0:
|
||||
return TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mf_info_try_lock(mfInfo* mfi, UINT32 ms)
|
||||
{
|
||||
int status = pthread_mutex_trylock(&mfi->mutex);
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case 0:
|
||||
return TRUE;
|
||||
break;
|
||||
|
||||
case EBUSY:
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mf_info_unlock(mfInfo* mfi)
|
||||
{
|
||||
int status = pthread_mutex_unlock(&mfi->mutex);
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case 0:
|
||||
return TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static mfInfo* mf_info_init(void)
|
||||
{
|
||||
mfInfo* mfi = (mfInfo*)calloc(1, sizeof(mfInfo));
|
||||
|
||||
if (mfi != nullptr)
|
||||
{
|
||||
pthread_mutex_init(&mfi->mutex, nullptr);
|
||||
|
||||
mfi->peers = (freerdp_peer**)calloc(MF_INFO_MAXPEERS, sizeof(freerdp_peer*));
|
||||
if (!mfi->peers)
|
||||
{
|
||||
free(mfi);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mfi->framesPerSecond = MF_INFO_DEFAULT_FPS;
|
||||
mfi->input_disabled = FALSE;
|
||||
}
|
||||
|
||||
return mfi;
|
||||
}
|
||||
|
||||
mfInfo* mf_info_get_instance(void)
|
||||
{
|
||||
if (mfInfoInstance == nullptr)
|
||||
mfInfoInstance = mf_info_init();
|
||||
|
||||
return mfInfoInstance;
|
||||
}
|
||||
|
||||
void mf_info_peer_register(mfInfo* mfi, mfPeerContext* context)
|
||||
{
|
||||
if (mf_info_lock(mfi) > 0)
|
||||
{
|
||||
int peerId;
|
||||
|
||||
if (mfi->peerCount == MF_INFO_MAXPEERS)
|
||||
{
|
||||
mf_info_unlock(mfi);
|
||||
return;
|
||||
}
|
||||
|
||||
context->info = mfi;
|
||||
|
||||
if (mfi->peerCount == 0)
|
||||
{
|
||||
mf_mlion_display_info(&mfi->servscreen_width, &mfi->servscreen_height, &mfi->scale);
|
||||
mf_mlion_screen_updates_init();
|
||||
mf_mlion_start_getting_screen_updates();
|
||||
}
|
||||
|
||||
peerId = 0;
|
||||
|
||||
for (int i = 0; i < MF_INFO_MAXPEERS; ++i)
|
||||
{
|
||||
// empty index will be our peer id
|
||||
if (mfi->peers[i] == nullptr)
|
||||
{
|
||||
peerId = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mfi->peers[peerId] = ((rdpContext*)context)->peer;
|
||||
mfi->peers[peerId]->pId = peerId;
|
||||
mfi->peerCount++;
|
||||
|
||||
mf_info_unlock(mfi);
|
||||
}
|
||||
}
|
||||
|
||||
void mf_info_peer_unregister(mfInfo* mfi, mfPeerContext* context)
|
||||
{
|
||||
if (mf_info_lock(mfi) > 0)
|
||||
{
|
||||
int peerId;
|
||||
|
||||
peerId = ((rdpContext*)context)->peer->pId;
|
||||
mfi->peers[peerId] = nullptr;
|
||||
mfi->peerCount--;
|
||||
|
||||
if (mfi->peerCount == 0)
|
||||
mf_mlion_stop_getting_screen_updates();
|
||||
|
||||
mf_info_unlock(mfi);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL mf_info_have_updates(mfInfo* mfi)
|
||||
{
|
||||
if (mfi->framesWaiting == 0)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void mf_info_update_changes(mfInfo* mfi)
|
||||
{
|
||||
}
|
||||
|
||||
void mf_info_find_invalid_region(mfInfo* mfi)
|
||||
{
|
||||
mf_mlion_get_dirty_region(&mfi->invalid);
|
||||
}
|
||||
|
||||
void mf_info_clear_invalid_region(mfInfo* mfi)
|
||||
{
|
||||
mf_mlion_clear_dirty_region();
|
||||
mfi->invalid.height = 0;
|
||||
mfi->invalid.width = 0;
|
||||
}
|
||||
|
||||
void mf_info_invalidate_full_screen(mfInfo* mfi)
|
||||
{
|
||||
mfi->invalid.x = 0;
|
||||
mfi->invalid.y = 0;
|
||||
mfi->invalid.height = mfi->servscreen_height;
|
||||
mfi->invalid.width = mfi->servscreen_width;
|
||||
}
|
||||
|
||||
BOOL mf_info_have_invalid_region(mfInfo* mfi)
|
||||
{
|
||||
if (mfi->invalid.width * mfi->invalid.height == 0)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void mf_info_getScreenData(mfInfo* mfi, long* width, long* height, BYTE** pBits, int* pitch)
|
||||
{
|
||||
*width = mfi->invalid.width / mfi->scale;
|
||||
*height = mfi->invalid.height / mfi->scale;
|
||||
*pitch = mfi->servscreen_width * mfi->scale * 4;
|
||||
|
||||
mf_mlion_get_pixelData(mfi->invalid.x / mfi->scale, mfi->invalid.y / mfi->scale, *width,
|
||||
*height, pBits);
|
||||
|
||||
*pBits = *pBits + (mfi->invalid.x * 4) + (*pitch * mfi->invalid.y);
|
||||
}
|
||||
49
third_party/FreeRDP/server/Mac/mf_info.h
vendored
Normal file
49
third_party/FreeRDP/server/Mac/mf_info.h
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Mac OS X 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_MAC_INFO_H
|
||||
#define FREERDP_SERVER_MAC_INFO_H
|
||||
|
||||
#define FREERDP_SERVER_MAC_INFO_DEFAULT_FPS 1
|
||||
#define FREERDP_SERVER_MAC_INFO_MAXPEERS 1
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
#include <freerdp/codec/rfx.h>
|
||||
|
||||
#include "mf_interface.h"
|
||||
|
||||
WINPR_ATTR_NODISCARD int mf_info_lock(mfInfo* mfi);
|
||||
WINPR_ATTR_NODISCARD int mf_info_try_lock(mfInfo* mfi, UINT32 ms);
|
||||
WINPR_ATTR_NODISCARD int mf_info_unlock(mfInfo* mfi);
|
||||
|
||||
WINPR_ATTR_NODISCARD mfInfo* mf_info_get_instance(void);
|
||||
void mf_info_peer_register(mfInfo* mfi, mfPeerContext* context);
|
||||
void mf_info_peer_unregister(mfInfo* mfi, mfPeerContext* context);
|
||||
|
||||
WINPR_ATTR_NODISCARD BOOL mf_info_have_updates(mfInfo* mfi);
|
||||
void mf_info_update_changes(mfInfo* mfi);
|
||||
void mf_info_find_invalid_region(mfInfo* mfi);
|
||||
void mf_info_clear_invalid_region(mfInfo* mfi);
|
||||
void mf_info_invalidate_full_screen(mfInfo* mfi);
|
||||
WINPR_ATTR_NODISCARD BOOL mf_info_have_invalid_region(mfInfo* mfi);
|
||||
void mf_info_getScreenData(mfInfo* mfi, long* width, long* height, BYTE** pBits, int* pitch);
|
||||
// BOOL CALLBACK mf_info_monEnumCB(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM
|
||||
// dwData);
|
||||
|
||||
#endif /* FREERDP_SERVER_MAC_INFO_H */
|
||||
511
third_party/FreeRDP/server/Mac/mf_input.c
vendored
Normal file
511
third_party/FreeRDP/server/Mac/mf_input.c
vendored
Normal file
@@ -0,0 +1,511 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Mac OS X Server (Input)
|
||||
*
|
||||
* 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 <ApplicationServices/ApplicationServices.h>
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
#include <winpr/windows.h>
|
||||
|
||||
#include "mf_input.h"
|
||||
#include "mf_info.h"
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG SERVER_TAG("mac")
|
||||
|
||||
static const CGKeyCode keymap[256] = {
|
||||
0xFF, // 0x0
|
||||
kVK_Escape, // 0x1
|
||||
kVK_ANSI_1, // 0x2
|
||||
kVK_ANSI_2, // 0x3
|
||||
kVK_ANSI_3, // 0x4
|
||||
kVK_ANSI_4, // 0x5
|
||||
kVK_ANSI_5, // 0x6
|
||||
kVK_ANSI_6, // 0x7
|
||||
kVK_ANSI_7, // 0x8
|
||||
kVK_ANSI_8, // 0x9
|
||||
kVK_ANSI_9, // 0xa
|
||||
kVK_ANSI_0, // 0xb
|
||||
kVK_ANSI_Minus, // 0xc
|
||||
kVK_ANSI_Equal, // 0xd
|
||||
kVK_Delete, // 0xe
|
||||
kVK_Tab, // 0xf
|
||||
kVK_ANSI_Q, // 0x10
|
||||
kVK_ANSI_W, // 0x11
|
||||
kVK_ANSI_E, // 0x12
|
||||
kVK_ANSI_R, // 0x13
|
||||
kVK_ANSI_T, // 0x14
|
||||
kVK_ANSI_Y, // 0x15
|
||||
kVK_ANSI_U, // 0x16
|
||||
kVK_ANSI_I, // 0x17
|
||||
kVK_ANSI_O, // 0x18
|
||||
kVK_ANSI_P, // 0x19
|
||||
kVK_ANSI_LeftBracket, // 0x1a
|
||||
kVK_ANSI_RightBracket, // 0x1b
|
||||
kVK_Return, // 0x1c
|
||||
kVK_Control, // 0x1d
|
||||
kVK_ANSI_A, // 0x1e
|
||||
kVK_ANSI_S, // 0x1f
|
||||
kVK_ANSI_D, // 0x20
|
||||
kVK_ANSI_F, // 0x21
|
||||
kVK_ANSI_G, // 0x22
|
||||
kVK_ANSI_H, // 0x23
|
||||
kVK_ANSI_J, // 0x24
|
||||
kVK_ANSI_K, // 0x25
|
||||
kVK_ANSI_L, // 0x26
|
||||
kVK_ANSI_Semicolon, // 0x27
|
||||
kVK_ANSI_Quote, // 0x28
|
||||
kVK_ANSI_Grave, // 0x29
|
||||
kVK_Shift, // 0x2a
|
||||
kVK_ANSI_Backslash, // 0x2b
|
||||
kVK_ANSI_Z, // 0x2c
|
||||
kVK_ANSI_X, // 0x2d
|
||||
kVK_ANSI_C, // 0x2e
|
||||
kVK_ANSI_V, // 0x2f
|
||||
kVK_ANSI_B, // 0x30
|
||||
kVK_ANSI_N, // 0x31
|
||||
kVK_ANSI_M, // 0x32
|
||||
kVK_ANSI_Comma, // 0x33
|
||||
kVK_ANSI_Period, // 0x34
|
||||
kVK_ANSI_Slash, // 0x35
|
||||
kVK_Shift, // 0x36
|
||||
kVK_ANSI_KeypadMultiply, // 0x37
|
||||
kVK_Option, // 0x38
|
||||
kVK_Space, // 0x39
|
||||
kVK_CapsLock, // 0x3a
|
||||
kVK_F1, // 0x3b
|
||||
kVK_F2, // 0x3c
|
||||
kVK_F3, // 0x3d
|
||||
kVK_F4, // 0x3e
|
||||
kVK_F5, // 0x3f
|
||||
kVK_F6, // 0x40
|
||||
kVK_F7, // 0x41
|
||||
kVK_F8, // 0x42
|
||||
kVK_F9, // 0x43
|
||||
kVK_F10, // 0x44
|
||||
0xFF, // 0x45 -- numlock
|
||||
0xFF, // 0x46 -- scroll lock
|
||||
kVK_ANSI_Keypad7, // 0x47
|
||||
kVK_ANSI_Keypad8, // 0x48
|
||||
kVK_ANSI_Keypad9, // 0x49
|
||||
kVK_ANSI_KeypadMinus, // 0x4a
|
||||
kVK_ANSI_Keypad4, // 0x4b
|
||||
kVK_ANSI_Keypad5, // 0x4c
|
||||
kVK_ANSI_Keypad6, // 0x4d
|
||||
kVK_ANSI_KeypadPlus, // 0x4e
|
||||
kVK_ANSI_Keypad1, // 0x4f
|
||||
kVK_ANSI_Keypad2, // 0x50
|
||||
kVK_ANSI_Keypad3, // 0x51
|
||||
kVK_ANSI_Keypad0, // 0x52
|
||||
kVK_ANSI_KeypadDecimal, // 0x53
|
||||
0xFF, // 0x54
|
||||
0xFF, // 0x55
|
||||
0xFF, // 0x56
|
||||
kVK_F11, // 0x57
|
||||
kVK_F12, // 0x58
|
||||
0xFF, // 0x59 -- pause
|
||||
0xFF, // 0x5a
|
||||
kVK_Control, // 0x5b
|
||||
kVK_Control, // 0x5c
|
||||
0xFF, // 0x5d -- application
|
||||
0xFF, // 0x5e -- power
|
||||
0xFF, // 0x5f -- sleep
|
||||
0xFF, // 0x60
|
||||
0xFF, // 0x61
|
||||
0xFF, // 0x62
|
||||
0xFF, // 0x63 -- wake
|
||||
0xFF, // 0x64
|
||||
0xFF, // 0x65
|
||||
0xFF, // 0x66
|
||||
0xFF, // 0x67
|
||||
0xFF, // 0x68
|
||||
0xFF, // 0x69
|
||||
0xFF, // 0x6a
|
||||
0xFF, // 0x6b
|
||||
0xFF, // 0x6c
|
||||
0xFF, // 0x6d
|
||||
0xFF, // 0x6e
|
||||
0xFF, // 0x6f
|
||||
0xFF, // 0x70
|
||||
0xFF, // 0x71
|
||||
0xFF, // 0x72
|
||||
0xFF, // 0x73
|
||||
0xFF, // 0x74
|
||||
0xFF, // 0x75
|
||||
0xFF, // 0x76
|
||||
0xFF, // 0x77
|
||||
0xFF, // 0x78
|
||||
0xFF, // 0x79
|
||||
0xFF, // 0x7a
|
||||
0xFF, // 0x7b
|
||||
0xFF, // 0x7c
|
||||
0xFF, // 0x7d
|
||||
0xFF, // 0x7e
|
||||
0xFF, // 0x7f
|
||||
0xFF, // 0x80
|
||||
0xFF, // 0x81
|
||||
0xFF, // 0x82
|
||||
0xFF, // 0x83
|
||||
0xFF, // 0x84
|
||||
0xFF, // 0x85
|
||||
0xFF, // 0x86
|
||||
0xFF, // 0x87
|
||||
0xFF, // 0x88
|
||||
0xFF, // 0x89
|
||||
0xFF, // 0x8a
|
||||
0xFF, // 0x8b
|
||||
0xFF, // 0x8c
|
||||
0xFF, // 0x8d
|
||||
0xFF, // 0x8e
|
||||
0xFF, // 0x8f
|
||||
0xFF, // 0x90
|
||||
0xFF, // 0x91
|
||||
0xFF, // 0x92
|
||||
0xFF, // 0x93
|
||||
0xFF, // 0x94
|
||||
0xFF, // 0x95
|
||||
0xFF, // 0x96
|
||||
0xFF, // 0x97
|
||||
0xFF, // 0x98
|
||||
0xFF, // 0x99
|
||||
0xFF, // 0x9a
|
||||
0xFF, // 0x9b
|
||||
0xFF, // 0x9c
|
||||
0xFF, // 0x9d
|
||||
0xFF, // 0x9e
|
||||
0xFF, // 0x9f
|
||||
0xFF, // 0xa0
|
||||
0xFF, // 0xa1
|
||||
0xFF, // 0xa2
|
||||
0xFF, // 0xa3
|
||||
0xFF, // 0xa4
|
||||
0xFF, // 0xa5
|
||||
0xFF, // 0xa6
|
||||
0xFF, // 0xa7
|
||||
0xFF, // 0xa8
|
||||
0xFF, // 0xa9
|
||||
0xFF, // 0xaa
|
||||
0xFF, // 0xab
|
||||
0xFF, // 0xac
|
||||
0xFF, // 0xad
|
||||
0xFF, // 0xae
|
||||
0xFF, // 0xaf
|
||||
0xFF, // 0xb0
|
||||
0xFF, // 0xb1
|
||||
0xFF, // 0xb2
|
||||
0xFF, // 0xb3
|
||||
0xFF, // 0xb4
|
||||
0xFF, // 0xb5
|
||||
0xFF, // 0xb6
|
||||
0xFF, // 0xb7
|
||||
0xFF, // 0xb8
|
||||
0xFF, // 0xb9
|
||||
0xFF, // 0xba
|
||||
0xFF, // 0xbb
|
||||
0xFF, // 0xbc
|
||||
0xFF, // 0xbd
|
||||
0xFF, // 0xbe
|
||||
0xFF, // 0xbf
|
||||
0xFF, // 0xc0
|
||||
0xFF, // 0xc1
|
||||
0xFF, // 0xc2
|
||||
0xFF, // 0xc3
|
||||
0xFF, // 0xc4
|
||||
0xFF, // 0xc5
|
||||
0xFF, // 0xc6
|
||||
0xFF, // 0xc7
|
||||
0xFF, // 0xc8
|
||||
0xFF, // 0xc9
|
||||
0xFF, // 0xca
|
||||
0xFF, // 0xcb
|
||||
0xFF, // 0xcc
|
||||
0xFF, // 0xcd
|
||||
0xFF, // 0xce
|
||||
0xFF, // 0xcf
|
||||
0xFF, // 0xd0
|
||||
0xFF, // 0xd1
|
||||
0xFF, // 0xd2
|
||||
0xFF, // 0xd3
|
||||
0xFF, // 0xd4
|
||||
0xFF, // 0xd5
|
||||
0xFF, // 0xd6
|
||||
0xFF, // 0xd7
|
||||
0xFF, // 0xd8
|
||||
0xFF, // 0xd9
|
||||
0xFF, // 0xda
|
||||
0xFF, // 0xdb
|
||||
0xFF, // 0xdc
|
||||
0xFF, // 0xdd
|
||||
0xFF, // 0xde
|
||||
0xFF, // 0xdf
|
||||
0xFF, // 0xe0
|
||||
0xFF, // 0xe1
|
||||
0xFF, // 0xe2
|
||||
0xFF, // 0xe3
|
||||
0xFF, // 0xe4
|
||||
0xFF, // 0xe5
|
||||
0xFF, // 0xe6
|
||||
0xFF, // 0xe7
|
||||
0xFF, // 0xe8
|
||||
0xFF, // 0xe9
|
||||
0xFF, // 0xea
|
||||
0xFF, // 0xeb
|
||||
0xFF, // 0xec
|
||||
0xFF, // 0xed
|
||||
0xFF, // 0xee
|
||||
0xFF, // 0xef
|
||||
0xFF, // 0xf0
|
||||
0xFF, // 0xf1
|
||||
0xFF, // 0xf2
|
||||
0xFF, // 0xf3
|
||||
0xFF, // 0xf4
|
||||
0xFF, // 0xf5
|
||||
0xFF, // 0xf6
|
||||
0xFF, // 0xf7
|
||||
0xFF, // 0xf8
|
||||
0xFF, // 0xf9
|
||||
0xFF, // 0xfa
|
||||
0xFF, // 0xfb
|
||||
0xFF, // 0xfc
|
||||
0xFF, // 0xfd
|
||||
0xFF, // 0xfe
|
||||
};
|
||||
|
||||
BOOL mf_input_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code)
|
||||
{
|
||||
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||
BOOL keyDown = TRUE;
|
||||
CGEventRef kbEvent;
|
||||
CGKeyCode kCode = 0xFF;
|
||||
|
||||
if (flags & KBD_FLAGS_RELEASE)
|
||||
{
|
||||
keyDown = FALSE;
|
||||
}
|
||||
|
||||
if (flags & KBD_FLAGS_EXTENDED)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
// case 0x52: //insert
|
||||
case 0x53:
|
||||
kCode = kVK_ForwardDelete;
|
||||
break;
|
||||
|
||||
case 0x4B:
|
||||
kCode = kVK_LeftArrow;
|
||||
break;
|
||||
|
||||
case 0x47:
|
||||
kCode = kVK_Home;
|
||||
break;
|
||||
|
||||
case 0x4F:
|
||||
kCode = kVK_End;
|
||||
break;
|
||||
|
||||
case 0x48:
|
||||
kCode = kVK_UpArrow;
|
||||
break;
|
||||
|
||||
case 0x50:
|
||||
kCode = kVK_DownArrow;
|
||||
break;
|
||||
|
||||
case 0x49:
|
||||
kCode = kVK_PageUp;
|
||||
break;
|
||||
|
||||
case 0x51:
|
||||
kCode = kVK_PageDown;
|
||||
break;
|
||||
|
||||
case 0x4D:
|
||||
kCode = kVK_RightArrow;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
kCode = keymap[code];
|
||||
}
|
||||
|
||||
kbEvent = CGEventCreateKeyboardEvent(source, kCode, keyDown);
|
||||
CGEventPost(kCGHIDEventTap, kbEvent);
|
||||
CFRelease(kbEvent);
|
||||
CFRelease(source);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL mf_input_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL mf_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
|
||||
{
|
||||
float width, height;
|
||||
CGWheelCount wheelCount = 2;
|
||||
INT32 scroll_x = 0;
|
||||
INT32 scroll_y = 0;
|
||||
|
||||
if (flags & (PTR_FLAGS_WHEEL | PTR_FLAGS_HWHEEL))
|
||||
{
|
||||
INT32 scroll = flags & WheelRotationMask;
|
||||
|
||||
if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
|
||||
scroll = -(flags & WheelRotationMask) / 392;
|
||||
else
|
||||
scroll = (flags & WheelRotationMask) / 120;
|
||||
|
||||
if (flags & PTR_FLAGS_WHEEL)
|
||||
scroll_y = scroll;
|
||||
else
|
||||
scroll_x = scroll;
|
||||
|
||||
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||
CGEventRef scrollEvent = CGEventCreateScrollWheelEvent(source, kCGScrollEventUnitLine,
|
||||
wheelCount, scroll_y, scroll_x);
|
||||
CGEventPost(kCGHIDEventTap, scrollEvent);
|
||||
CFRelease(scrollEvent);
|
||||
CFRelease(source);
|
||||
}
|
||||
else
|
||||
{
|
||||
mfInfo* mfi;
|
||||
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||
CGEventType mouseType = kCGEventNull;
|
||||
CGMouseButton mouseButton = kCGMouseButtonLeft;
|
||||
mfi = mf_info_get_instance();
|
||||
// width and height of primary screen (even in multimon setups
|
||||
width = (float)mfi->servscreen_width;
|
||||
height = (float)mfi->servscreen_height;
|
||||
x += mfi->servscreen_xoffset;
|
||||
y += mfi->servscreen_yoffset;
|
||||
|
||||
if (flags & PTR_FLAGS_MOVE)
|
||||
{
|
||||
if (mfi->mouse_down_left == TRUE)
|
||||
{
|
||||
mouseType = kCGEventLeftMouseDragged;
|
||||
}
|
||||
else if (mfi->mouse_down_right == TRUE)
|
||||
{
|
||||
mouseType = kCGEventRightMouseDragged;
|
||||
}
|
||||
else if (mfi->mouse_down_other == TRUE)
|
||||
{
|
||||
mouseType = kCGEventOtherMouseDragged;
|
||||
}
|
||||
else
|
||||
{
|
||||
mouseType = kCGEventMouseMoved;
|
||||
}
|
||||
|
||||
CGEventRef move = CGEventCreateMouseEvent(source, mouseType, CGPointMake(x, y),
|
||||
mouseButton // ignored for just movement
|
||||
);
|
||||
CGEventPost(kCGHIDEventTap, move);
|
||||
CFRelease(move);
|
||||
}
|
||||
|
||||
if (flags & PTR_FLAGS_BUTTON1)
|
||||
{
|
||||
mouseButton = kCGMouseButtonLeft;
|
||||
|
||||
if (flags & PTR_FLAGS_DOWN)
|
||||
{
|
||||
mouseType = kCGEventLeftMouseDown;
|
||||
mfi->mouse_down_left = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mouseType = kCGEventLeftMouseUp;
|
||||
mfi->mouse_down_right = FALSE;
|
||||
}
|
||||
}
|
||||
else if (flags & PTR_FLAGS_BUTTON2)
|
||||
{
|
||||
mouseButton = kCGMouseButtonRight;
|
||||
|
||||
if (flags & PTR_FLAGS_DOWN)
|
||||
{
|
||||
mouseType = kCGEventRightMouseDown;
|
||||
mfi->mouse_down_right = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mouseType = kCGEventRightMouseUp;
|
||||
mfi->mouse_down_right = FALSE;
|
||||
}
|
||||
}
|
||||
else if (flags & PTR_FLAGS_BUTTON3)
|
||||
{
|
||||
mouseButton = kCGMouseButtonCenter;
|
||||
|
||||
if (flags & PTR_FLAGS_DOWN)
|
||||
{
|
||||
mouseType = kCGEventOtherMouseDown;
|
||||
mfi->mouse_down_other = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mouseType = kCGEventOtherMouseUp;
|
||||
mfi->mouse_down_other = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
CGEventRef mouseEvent =
|
||||
CGEventCreateMouseEvent(source, mouseType, CGPointMake(x, y), mouseButton);
|
||||
CGEventPost(kCGHIDEventTap, mouseEvent);
|
||||
CFRelease(mouseEvent);
|
||||
CFRelease(source);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL mf_input_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL mf_input_keyboard_event_dummy(rdpInput* input, UINT16 flags, UINT16 code)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL mf_input_unicode_keyboard_event_dummy(rdpInput* input, UINT16 flags, UINT16 code)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL mf_input_mouse_event_dummy(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL mf_input_extended_mouse_event_dummy(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
41
third_party/FreeRDP/server/Mac/mf_input.h
vendored
Normal file
41
third_party/FreeRDP/server/Mac/mf_input.h
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Mac OS X Server (Input)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_MAC_INPUT_H
|
||||
#define FREERDP_SERVER_MAC_INPUT_H
|
||||
|
||||
#include "mf_interface.h"
|
||||
|
||||
WINPR_ATTR_NODISCARD BOOL mf_input_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code);
|
||||
WINPR_ATTR_NODISCARD BOOL mf_input_unicode_keyboard_event(rdpInput* input, UINT16 flags,
|
||||
UINT16 code);
|
||||
WINPR_ATTR_NODISCARD BOOL mf_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y);
|
||||
WINPR_ATTR_NODISCARD BOOL mf_input_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x,
|
||||
UINT16 y);
|
||||
|
||||
// dummy versions
|
||||
WINPR_ATTR_NODISCARD BOOL mf_input_keyboard_event_dummy(rdpInput* input, UINT16 flags, UINT16 code);
|
||||
WINPR_ATTR_NODISCARD BOOL mf_input_unicode_keyboard_event_dummy(rdpInput* input, UINT16 flags,
|
||||
UINT16 code);
|
||||
WINPR_ATTR_NODISCARD BOOL mf_input_mouse_event_dummy(rdpInput* input, UINT16 flags, UINT16 x,
|
||||
UINT16 y);
|
||||
WINPR_ATTR_NODISCARD BOOL mf_input_extended_mouse_event_dummy(rdpInput* input, UINT16 flags,
|
||||
UINT16 x, UINT16 y);
|
||||
|
||||
#endif /* FREERDP_SERVER_MAC_INPUT_H */
|
||||
0
third_party/FreeRDP/server/Mac/mf_interface.c
vendored
Normal file
0
third_party/FreeRDP/server/Mac/mf_interface.c
vendored
Normal file
106
third_party/FreeRDP/server/Mac/mf_interface.h
vendored
Normal file
106
third_party/FreeRDP/server/Mac/mf_interface.h
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Client
|
||||
* FreeRDP Mac OS X 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_MAC_INTERFACE_H
|
||||
#define FREERDP_SERVER_MAC_INTERFACE_H
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <freerdp/config.h>
|
||||
#include <freerdp/codec/rfx.h>
|
||||
#include <freerdp/codec/nsc.h>
|
||||
#include <freerdp/listener.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#ifdef WITH_SERVER_CHANNELS
|
||||
#include <freerdp/channels/wtsvc.h>
|
||||
#endif
|
||||
|
||||
#ifdef CHANNEL_RDPSND_SERVER
|
||||
#include <freerdp/server/rdpsnd.h>
|
||||
#include "mf_rdpsnd.h"
|
||||
#endif
|
||||
|
||||
#ifdef CHANNEL_AUDIN_SERVER
|
||||
#include <freerdp/server/audin.h>
|
||||
#include "mf_audin.h"
|
||||
#endif
|
||||
|
||||
#include "mf_types.h"
|
||||
|
||||
struct mf_peer_context
|
||||
{
|
||||
rdpContext _p;
|
||||
|
||||
mfInfo* info;
|
||||
wStream* s;
|
||||
BOOL activated;
|
||||
UINT32 frame_id;
|
||||
BOOL audin_open;
|
||||
RFX_CONTEXT* rfx_context;
|
||||
NSC_CONTEXT* nsc_context;
|
||||
|
||||
#ifdef WITH_SERVER_CHANNELS
|
||||
HANDLE vcm;
|
||||
#endif
|
||||
|
||||
#ifdef CHANNEL_AUDIN_SERVER
|
||||
audin_server_context* audin;
|
||||
#endif
|
||||
|
||||
#ifdef CHANNEL_RDPSND_SERVER
|
||||
RdpsndServerContext* rdpsnd;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct mf_info
|
||||
{
|
||||
// STREAM* s;
|
||||
|
||||
// screen and monitor info
|
||||
UINT32 screenID;
|
||||
UINT32 virtscreen_width;
|
||||
UINT32 virtscreen_height;
|
||||
UINT32 servscreen_width;
|
||||
UINT32 servscreen_height;
|
||||
UINT32 servscreen_xoffset;
|
||||
UINT32 servscreen_yoffset;
|
||||
|
||||
int bitsPerPixel;
|
||||
int peerCount;
|
||||
int activePeerCount;
|
||||
int framesPerSecond;
|
||||
freerdp_peer** peers;
|
||||
unsigned int framesWaiting;
|
||||
UINT32 scale;
|
||||
|
||||
RFX_RECT invalid;
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
BOOL mouse_down_left;
|
||||
BOOL mouse_down_right;
|
||||
BOOL mouse_down_other;
|
||||
BOOL input_disabled;
|
||||
BOOL force_all_disconnect;
|
||||
};
|
||||
|
||||
#endif /* FREERDP_SERVER_MAC_INTERFACE_H */
|
||||
269
third_party/FreeRDP/server/Mac/mf_mountain_lion.c
vendored
Normal file
269
third_party/FreeRDP/server/Mac/mf_mountain_lion.c
vendored
Normal file
@@ -0,0 +1,269 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* OS X Server Event Handling
|
||||
*
|
||||
* 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 <dispatch/dispatch.h>
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
#include <CoreVideo/CoreVideo.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOSurface/IOSurface.h>
|
||||
|
||||
#include "mf_mountain_lion.h"
|
||||
|
||||
dispatch_semaphore_t region_sem;
|
||||
dispatch_semaphore_t data_sem;
|
||||
dispatch_queue_t screen_update_q;
|
||||
CGDisplayStreamRef stream;
|
||||
|
||||
CGDisplayStreamUpdateRef lastUpdate = nullptr;
|
||||
|
||||
BYTE* localBuf = nullptr;
|
||||
|
||||
BOOL ready = FALSE;
|
||||
|
||||
void (^streamHandler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfaceRef,
|
||||
CGDisplayStreamUpdateRef) = ^(CGDisplayStreamFrameStatus status,
|
||||
uint64_t displayTime, IOSurfaceRef frameSurface,
|
||||
CGDisplayStreamUpdateRef updateRef) {
|
||||
dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
|
||||
|
||||
// may need to move this down
|
||||
if (ready == TRUE)
|
||||
{
|
||||
|
||||
RFX_RECT rect;
|
||||
unsigned long offset_beg;
|
||||
unsigned long stride;
|
||||
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.width = 0;
|
||||
rect.height = 0;
|
||||
mf_mlion_peek_dirty_region(&rect);
|
||||
|
||||
// lock surface
|
||||
IOSurfaceLock(frameSurface, kIOSurfaceLockReadOnly, nullptr);
|
||||
// get pointer
|
||||
void* baseAddress = IOSurfaceGetBaseAddress(frameSurface);
|
||||
// copy region
|
||||
|
||||
stride = IOSurfaceGetBytesPerRow(frameSurface);
|
||||
// memcpy(localBuf, baseAddress + offset_beg, surflen);
|
||||
for (int i = 0; i < rect.height; i++)
|
||||
{
|
||||
offset_beg = (stride * (rect.y + i) + (rect.x * 4));
|
||||
memcpy(localBuf + offset_beg, baseAddress + offset_beg, rect.width * 4);
|
||||
}
|
||||
|
||||
// unlock surface
|
||||
IOSurfaceUnlock(frameSurface, kIOSurfaceLockReadOnly, nullptr);
|
||||
|
||||
ready = FALSE;
|
||||
dispatch_semaphore_signal(data_sem);
|
||||
}
|
||||
|
||||
if (status != kCGDisplayStreamFrameStatusFrameComplete)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case kCGDisplayStreamFrameStatusFrameIdle:
|
||||
break;
|
||||
|
||||
case kCGDisplayStreamFrameStatusStopped:
|
||||
break;
|
||||
|
||||
case kCGDisplayStreamFrameStatusFrameBlank:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (lastUpdate == nullptr)
|
||||
{
|
||||
CFRetain(updateRef);
|
||||
lastUpdate = updateRef;
|
||||
}
|
||||
else
|
||||
{
|
||||
CGDisplayStreamUpdateRef tmpRef;
|
||||
tmpRef = lastUpdate;
|
||||
lastUpdate = CGDisplayStreamUpdateCreateMergedUpdate(tmpRef, updateRef);
|
||||
CFRelease(tmpRef);
|
||||
}
|
||||
|
||||
dispatch_semaphore_signal(region_sem);
|
||||
};
|
||||
|
||||
int mf_mlion_display_info(UINT32* disp_width, UINT32* disp_height, UINT32* scale)
|
||||
{
|
||||
CGDirectDisplayID display_id;
|
||||
|
||||
display_id = CGMainDisplayID();
|
||||
|
||||
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display_id);
|
||||
|
||||
size_t pixelWidth = CGDisplayModeGetPixelWidth(mode);
|
||||
// size_t pixelHeight = CGDisplayModeGetPixelHeight(mode);
|
||||
|
||||
size_t wide = CGDisplayPixelsWide(display_id);
|
||||
size_t high = CGDisplayPixelsHigh(display_id);
|
||||
|
||||
CGDisplayModeRelease(mode);
|
||||
|
||||
*disp_width = wide; // pixelWidth;
|
||||
*disp_height = high; // pixelHeight;
|
||||
*scale = pixelWidth / wide;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mf_mlion_screen_updates_init()
|
||||
{
|
||||
CGDirectDisplayID display_id;
|
||||
|
||||
display_id = CGMainDisplayID();
|
||||
|
||||
screen_update_q = dispatch_queue_create("mfreerdp.server.screenUpdate", nullptr);
|
||||
|
||||
region_sem = dispatch_semaphore_create(1);
|
||||
data_sem = dispatch_semaphore_create(1);
|
||||
|
||||
UINT32 pixelWidth;
|
||||
UINT32 pixelHeight;
|
||||
UINT32 scale;
|
||||
|
||||
mf_mlion_display_info(&pixelWidth, &pixelHeight, &scale);
|
||||
|
||||
localBuf = malloc(pixelWidth * pixelHeight * 4);
|
||||
if (!localBuf)
|
||||
return -1;
|
||||
|
||||
CFDictionaryRef opts;
|
||||
|
||||
void* keys[2];
|
||||
void* values[2];
|
||||
|
||||
keys[0] = (void*)kCGDisplayStreamShowCursor;
|
||||
values[0] = (void*)kCFBooleanFalse;
|
||||
|
||||
opts = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)values, 1,
|
||||
nullptr, nullptr);
|
||||
|
||||
stream = CGDisplayStreamCreateWithDispatchQueue(display_id, pixelWidth, pixelHeight, 'BGRA',
|
||||
opts, screen_update_q, streamHandler);
|
||||
|
||||
CFRelease(opts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mf_mlion_start_getting_screen_updates()
|
||||
{
|
||||
CGError err;
|
||||
|
||||
err = CGDisplayStreamStart(stream);
|
||||
|
||||
if (err != kCGErrorSuccess)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
int mf_mlion_stop_getting_screen_updates()
|
||||
{
|
||||
CGError err;
|
||||
|
||||
err = CGDisplayStreamStop(stream);
|
||||
|
||||
if (err != kCGErrorSuccess)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mf_mlion_get_dirty_region(RFX_RECT* invalid)
|
||||
{
|
||||
dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
|
||||
|
||||
if (lastUpdate != nullptr)
|
||||
{
|
||||
mf_mlion_peek_dirty_region(invalid);
|
||||
}
|
||||
|
||||
dispatch_semaphore_signal(region_sem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mf_mlion_peek_dirty_region(RFX_RECT* invalid)
|
||||
{
|
||||
size_t num_rects;
|
||||
CGRect dirtyRegion;
|
||||
|
||||
const CGRect* rects =
|
||||
CGDisplayStreamUpdateGetRects(lastUpdate, kCGDisplayStreamUpdateDirtyRects, &num_rects);
|
||||
|
||||
if (num_rects == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
dirtyRegion = *rects;
|
||||
for (size_t i = 0; i < num_rects; i++)
|
||||
{
|
||||
dirtyRegion = CGRectUnion(dirtyRegion, *(rects + i));
|
||||
}
|
||||
|
||||
invalid->x = dirtyRegion.origin.x;
|
||||
invalid->y = dirtyRegion.origin.y;
|
||||
invalid->height = dirtyRegion.size.height;
|
||||
invalid->width = dirtyRegion.size.width;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mf_mlion_clear_dirty_region()
|
||||
{
|
||||
dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
|
||||
|
||||
CFRelease(lastUpdate);
|
||||
lastUpdate = nullptr;
|
||||
|
||||
dispatch_semaphore_signal(region_sem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mf_mlion_get_pixelData(long x, long y, long width, long height, BYTE** pxData)
|
||||
{
|
||||
dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
|
||||
ready = TRUE;
|
||||
dispatch_semaphore_wait(data_sem, DISPATCH_TIME_FOREVER);
|
||||
dispatch_semaphore_signal(region_sem);
|
||||
|
||||
// this second wait allows us to block until data is copied... more on this later
|
||||
dispatch_semaphore_wait(data_sem, DISPATCH_TIME_FOREVER);
|
||||
*pxData = localBuf;
|
||||
dispatch_semaphore_signal(data_sem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
40
third_party/FreeRDP/server/Mac/mf_mountain_lion.h
vendored
Normal file
40
third_party/FreeRDP/server/Mac/mf_mountain_lion.h
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* OS X Server Event Handling
|
||||
*
|
||||
* 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_MAC_MLION_H
|
||||
#define FREERDP_SERVER_MAC_MLION_H
|
||||
|
||||
#include <freerdp/codec/rfx.h>
|
||||
|
||||
WINPR_ATTR_NODISCARD int mf_mlion_display_info(UINT32* disp_width, UINT32* dispHeight,
|
||||
UINT32* scale);
|
||||
|
||||
WINPR_ATTR_NODISCARD int mf_mlion_screen_updates_init(void);
|
||||
|
||||
WINPR_ATTR_NODISCARD int mf_mlion_start_getting_screen_updates(void);
|
||||
WINPR_ATTR_NODISCARD int mf_mlion_stop_getting_screen_updates(void);
|
||||
|
||||
WINPR_ATTR_NODISCARD int mf_mlion_get_dirty_region(RFX_RECT* invalid);
|
||||
WINPR_ATTR_NODISCARD int mf_mlion_peek_dirty_region(RFX_RECT* invalid);
|
||||
WINPR_ATTR_NODISCARD int mf_mlion_clear_dirty_region(void);
|
||||
|
||||
WINPR_ATTR_NODISCARD int mf_mlion_get_pixelData(long x, long y, long width, long height,
|
||||
BYTE** pxData);
|
||||
|
||||
#endif /* FREERDP_SERVER_MAC_MLION_H */
|
||||
496
third_party/FreeRDP/server/Mac/mf_peer.c
vendored
Normal file
496
third_party/FreeRDP/server/Mac/mf_peer.c
vendored
Normal file
@@ -0,0 +1,496 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Client
|
||||
* FreeRDP Mac OS X 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 <freerdp/listener.h>
|
||||
#include <freerdp/codec/rfx.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <freerdp/peer.h>
|
||||
#include <freerdp/codec/color.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include "mf_peer.h"
|
||||
#include "mf_info.h"
|
||||
#include "mf_input.h"
|
||||
#include "mf_event.h"
|
||||
#include "mf_rdpsnd.h"
|
||||
#include "mf_audin.h"
|
||||
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
|
||||
#include "OpenGL/OpenGL.h"
|
||||
#include "OpenGL/gl.h"
|
||||
|
||||
#include "CoreVideo/CoreVideo.h"
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG SERVER_TAG("mac")
|
||||
|
||||
// refactor these
|
||||
static int info_last_sec = 0;
|
||||
static int info_last_nsec = 0;
|
||||
|
||||
static dispatch_source_t info_timer;
|
||||
static dispatch_queue_t info_queue;
|
||||
|
||||
static mfEventQueue* info_event_queue;
|
||||
|
||||
static CGLContextObj glContext;
|
||||
static CGContextRef bmp;
|
||||
static CGImageRef img;
|
||||
|
||||
static void mf_peer_context_free(freerdp_peer* client, rdpContext* context);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL mf_peer_get_fds(freerdp_peer* client, void** rfds, int* rcount)
|
||||
{
|
||||
if (info_event_queue->pipe_fd[0] == -1)
|
||||
return TRUE;
|
||||
|
||||
rfds[*rcount] = (void*)(long)info_event_queue->pipe_fd[0];
|
||||
(*rcount)++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void mf_peer_rfx_update(freerdp_peer* client)
|
||||
{
|
||||
// check
|
||||
mfInfo* mfi = mf_info_get_instance();
|
||||
mf_info_find_invalid_region(mfi);
|
||||
|
||||
if (mf_info_have_invalid_region(mfi) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
long width;
|
||||
long height;
|
||||
int pitch;
|
||||
BYTE* dataBits = nullptr;
|
||||
mf_info_getScreenData(mfi, &width, &height, &dataBits, &pitch);
|
||||
mf_info_clear_invalid_region(mfi);
|
||||
// encode
|
||||
wStream* s;
|
||||
RFX_RECT rect;
|
||||
rdpUpdate* update;
|
||||
mfPeerContext* mfp;
|
||||
SURFACE_BITS_COMMAND cmd = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_ASSERT(client);
|
||||
|
||||
mfp = (mfPeerContext*)client->context;
|
||||
WINPR_ASSERT(mfp);
|
||||
|
||||
update = client->context->update;
|
||||
WINPR_ASSERT(update);
|
||||
|
||||
s = mfp->s;
|
||||
WINPR_ASSERT(s);
|
||||
|
||||
Stream_Clear(s);
|
||||
Stream_ResetPosition(s);
|
||||
UINT32 x = mfi->invalid.x / mfi->scale;
|
||||
UINT32 y = mfi->invalid.y / mfi->scale;
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.width = width;
|
||||
rect.height = height;
|
||||
|
||||
rfx_context_reset(mfp->rfx_context, mfi->servscreen_width, mfi->servscreen_height);
|
||||
|
||||
if (!(rfx_compose_message(mfp->rfx_context, s, &rect, 1, (BYTE*)dataBits, rect.width,
|
||||
rect.height, pitch)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cmd.destLeft = x;
|
||||
cmd.destTop = y;
|
||||
cmd.destRight = x + rect.width;
|
||||
cmd.destBottom = y + rect.height;
|
||||
cmd.bmp.bpp = 32;
|
||||
cmd.bmp.codecID = 3;
|
||||
cmd.bmp.width = rect.width;
|
||||
cmd.bmp.height = rect.height;
|
||||
cmd.bmp.bitmapDataLength = Stream_GetPosition(s);
|
||||
cmd.bmp.bitmapData = Stream_Buffer(s);
|
||||
// send
|
||||
update->SurfaceBits(update->context, &cmd);
|
||||
// clean up... maybe?
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL mf_peer_check_fds(freerdp_peer* client)
|
||||
{
|
||||
mfPeerContext* context = (mfPeerContext*)client->context;
|
||||
mfEvent* event;
|
||||
|
||||
if (context->activated == FALSE)
|
||||
return TRUE;
|
||||
|
||||
event = mf_event_peek(info_event_queue);
|
||||
|
||||
if (event != nullptr)
|
||||
{
|
||||
if (event->type == FREERDP_SERVER_MAC_EVENT_TYPE_REGION)
|
||||
{
|
||||
}
|
||||
else if (event->type == FREERDP_SERVER_MAC_EVENT_TYPE_FRAME_TICK)
|
||||
{
|
||||
event = mf_event_pop(info_event_queue);
|
||||
mf_peer_rfx_update(client);
|
||||
mf_event_free(event);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Called when we have a new peer connecting */
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL mf_peer_context_new(freerdp_peer* client, rdpContext* context)
|
||||
{
|
||||
rdpSettings* settings;
|
||||
mfPeerContext* peer = (mfPeerContext*)context;
|
||||
|
||||
WINPR_ASSERT(client);
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
settings = context->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
if (!(peer->info = mf_info_get_instance()))
|
||||
return FALSE;
|
||||
|
||||
if (!(peer->rfx_context = rfx_context_new_ex(
|
||||
TRUE, freerdp_settings_get_uint32(settings, FreeRDP_ThreadingFlags))))
|
||||
goto fail;
|
||||
|
||||
rfx_context_reset(peer->rfx_context,
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight));
|
||||
rfx_context_set_mode(peer->rfx_context, RLGR3);
|
||||
rfx_context_set_pixel_format(peer->rfx_context, PIXEL_FORMAT_BGRA32);
|
||||
|
||||
if (!(peer->s = Stream_New(nullptr, 0xFFFF)))
|
||||
goto fail;
|
||||
|
||||
peer->vcm = WTSOpenServerA((LPSTR)client->context);
|
||||
|
||||
if (!peer->vcm || (peer->vcm == INVALID_HANDLE_VALUE))
|
||||
goto fail;
|
||||
|
||||
mf_info_peer_register(peer->info, peer);
|
||||
return TRUE;
|
||||
fail:
|
||||
mf_peer_context_free(client, context);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Called after a peer disconnects */
|
||||
static void mf_peer_context_free(freerdp_peer* client, rdpContext* context)
|
||||
{
|
||||
mfPeerContext* peer = (mfPeerContext*)context;
|
||||
if (context)
|
||||
{
|
||||
mf_info_peer_unregister(peer->info, peer);
|
||||
dispatch_suspend(info_timer);
|
||||
Stream_Free(peer->s, TRUE);
|
||||
rfx_context_free(peer->rfx_context);
|
||||
// nsc_context_free(peer->nsc_context);
|
||||
#ifdef CHANNEL_AUDIN_SERVER
|
||||
|
||||
mf_peer_audin_uninit(peer);
|
||||
|
||||
#endif
|
||||
#ifdef CHANNEL_RDPSND_SERVER
|
||||
mf_peer_rdpsnd_stop();
|
||||
|
||||
if (peer->rdpsnd)
|
||||
rdpsnd_server_context_free(peer->rdpsnd);
|
||||
|
||||
#endif
|
||||
WTSCloseServer(peer->vcm);
|
||||
}
|
||||
}
|
||||
|
||||
/* Called when a new client connects */
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL mf_peer_init(freerdp_peer* client)
|
||||
{
|
||||
client->ContextSize = sizeof(mfPeerContext);
|
||||
client->ContextNew = mf_peer_context_new;
|
||||
client->ContextFree = mf_peer_context_free;
|
||||
|
||||
if (!freerdp_peer_context_new(client))
|
||||
return FALSE;
|
||||
|
||||
info_event_queue = mf_event_queue_new();
|
||||
info_queue = dispatch_queue_create("FreeRDP.update.timer", DISPATCH_QUEUE_SERIAL);
|
||||
info_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, info_queue);
|
||||
|
||||
if (info_timer)
|
||||
{
|
||||
// DEBUG_WARN( "created timer\n");
|
||||
dispatch_source_set_timer(info_timer, DISPATCH_TIME_NOW, 42ull * NSEC_PER_MSEC,
|
||||
100ull * NSEC_PER_MSEC);
|
||||
dispatch_source_set_event_handler(info_timer, ^{
|
||||
// DEBUG_WARN( "dispatch\n");
|
||||
mfEvent* event = mf_event_new(FREERDP_SERVER_MAC_EVENT_TYPE_FRAME_TICK);
|
||||
mf_event_push(info_event_queue, (mfEvent*)event);
|
||||
});
|
||||
dispatch_resume(info_timer);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL mf_peer_post_connect(freerdp_peer* client)
|
||||
{
|
||||
mfInfo* mfi = mf_info_get_instance();
|
||||
|
||||
WINPR_ASSERT(client);
|
||||
|
||||
mfPeerContext* context = (mfPeerContext*)client->context;
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
rdpSettings* settings = client->context->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
mfi->scale = 1;
|
||||
// mfi->servscreen_width = 2880 / mfi->scale;
|
||||
// mfi->servscreen_height = 1800 / mfi->scale;
|
||||
UINT32 bitsPerPixel = 32;
|
||||
|
||||
if ((freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) != mfi->servscreen_width) ||
|
||||
(freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) != mfi->servscreen_height))
|
||||
{
|
||||
}
|
||||
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, mfi->servscreen_width))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, mfi->servscreen_height))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, bitsPerPixel))
|
||||
return FALSE;
|
||||
|
||||
WINPR_ASSERT(client->context->update);
|
||||
WINPR_ASSERT(client->context->update->DesktopResize);
|
||||
client->context->update->DesktopResize(client->context);
|
||||
|
||||
mfi->mouse_down_left = FALSE;
|
||||
mfi->mouse_down_right = FALSE;
|
||||
mfi->mouse_down_other = FALSE;
|
||||
#ifdef CHANNEL_RDPSND_SERVER
|
||||
|
||||
if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, "rdpsnd"))
|
||||
{
|
||||
mf_peer_rdpsnd_init(context); /* Audio Output */
|
||||
}
|
||||
|
||||
#endif
|
||||
/* Dynamic Virtual Channels */
|
||||
#ifdef CHANNEL_AUDIN_SERVER
|
||||
mf_peer_audin_init(context); /* Audio Input */
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL mf_peer_activate(freerdp_peer* client)
|
||||
{
|
||||
WINPR_ASSERT(client);
|
||||
|
||||
mfPeerContext* context = (mfPeerContext*)client->context;
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
rdpSettings* settings = client->context->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
rfx_context_reset(context->rfx_context,
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight));
|
||||
context->activated = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL mf_peer_synchronize_event(rdpInput* input, UINT32 flags)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL mf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code)
|
||||
{
|
||||
bool state_down = FALSE;
|
||||
|
||||
if (flags == KBD_FLAGS_DOWN)
|
||||
{
|
||||
state_down = TRUE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL mf_peer_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL mf_peer_suppress_output(rdpContext* context, BYTE allow, const RECTANGLE_16* area)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static void* mf_peer_main_loop(void* arg)
|
||||
{
|
||||
mfPeerContext* context;
|
||||
rdpSettings* settings;
|
||||
rdpInput* input;
|
||||
rdpUpdate* update;
|
||||
freerdp_peer* client = (freerdp_peer*)arg;
|
||||
|
||||
if (!mf_peer_init(client))
|
||||
goto fail;
|
||||
|
||||
const mf_server_info* info = client->ContextExtra;
|
||||
WINPR_ASSERT(info);
|
||||
|
||||
WINPR_ASSERT(client->context);
|
||||
|
||||
settings = client->context->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
/* Initialize the real server settings here */
|
||||
rdpPrivateKey* key = freerdp_key_new_from_file_enc(info->key, nullptr);
|
||||
if (!key)
|
||||
goto fail;
|
||||
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerRsaKey, key, 1))
|
||||
goto fail;
|
||||
rdpCertificate* cert = freerdp_certificate_new_from_file(info->cert);
|
||||
if (!cert)
|
||||
goto fail;
|
||||
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerCertificate, cert, 1))
|
||||
goto fail;
|
||||
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE))
|
||||
goto fail;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE))
|
||||
goto fail;
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, 32))
|
||||
goto fail;
|
||||
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_SuppressOutput, TRUE))
|
||||
goto fail;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_RefreshRect, FALSE))
|
||||
goto fail;
|
||||
|
||||
client->PostConnect = mf_peer_post_connect;
|
||||
client->Activate = mf_peer_activate;
|
||||
|
||||
input = client->context->input;
|
||||
WINPR_ASSERT(input);
|
||||
|
||||
input->SynchronizeEvent = mf_peer_synchronize_event;
|
||||
input->KeyboardEvent = mf_input_keyboard_event; // mf_peer_keyboard_event;
|
||||
input->UnicodeKeyboardEvent = mf_peer_unicode_keyboard_event;
|
||||
input->MouseEvent = mf_input_mouse_event;
|
||||
input->ExtendedMouseEvent = mf_input_extended_mouse_event;
|
||||
|
||||
update = client->context->update;
|
||||
WINPR_ASSERT(update);
|
||||
|
||||
// update->RefreshRect = mf_peer_refresh_rect;
|
||||
update->SuppressOutput = mf_peer_suppress_output;
|
||||
|
||||
WINPR_ASSERT(client->Initialize);
|
||||
const BOOL rc = client->Initialize(client);
|
||||
if (!rc)
|
||||
goto fail;
|
||||
context = (mfPeerContext*)client->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) || (count == MAXIMUM_WAIT_OBJECTS))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get FreeRDP file descriptor");
|
||||
break;
|
||||
}
|
||||
|
||||
handles[count++] = WTSVirtualChannelManagerGetEventHandle(context->vcm);
|
||||
|
||||
status = WaitForMultipleObjects(count, handles, FALSE, INFINITE);
|
||||
if (status == WAIT_FAILED)
|
||||
{
|
||||
WLog_ERR(TAG, "WaitForMultipleObjects failed");
|
||||
break;
|
||||
}
|
||||
|
||||
if (client->CheckFileDescriptor(client) != TRUE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ((mf_peer_check_fds(client)) != TRUE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
client->Disconnect(client);
|
||||
freerdp_peer_context_free(client);
|
||||
fail:
|
||||
freerdp_peer_free(client);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BOOL mf_peer_accepted(freerdp_listener* instance, freerdp_peer* client)
|
||||
{
|
||||
pthread_t th;
|
||||
|
||||
WINPR_ASSERT(instance);
|
||||
WINPR_ASSERT(client);
|
||||
|
||||
client->ContextExtra = instance->info;
|
||||
if (pthread_create(&th, 0, mf_peer_main_loop, client) == 0)
|
||||
{
|
||||
pthread_detach(th);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
33
third_party/FreeRDP/server/Mac/mf_peer.h
vendored
Normal file
33
third_party/FreeRDP/server/Mac/mf_peer.h
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Mac OS X 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_MAC_PEER_H
|
||||
#define FREERDP_SERVER_MAC_PEER_H
|
||||
|
||||
#include "mf_interface.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* cert;
|
||||
const char* key;
|
||||
} mf_server_info;
|
||||
|
||||
WINPR_ATTR_NODISCARD BOOL mf_peer_accepted(freerdp_listener* instance, freerdp_peer* client);
|
||||
|
||||
#endif /* FREERDP_SERVER_MAC_PEER_H */
|
||||
200
third_party/FreeRDP/server/Mac/mf_rdpsnd.c
vendored
Normal file
200
third_party/FreeRDP/server/Mac/mf_rdpsnd.c
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Mac OS X Server (Audio Output)
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <freerdp/server/rdpsnd.h>
|
||||
|
||||
#include "mf_info.h"
|
||||
#include "mf_rdpsnd.h"
|
||||
#include "mf_interface.h"
|
||||
|
||||
#include <winpr/sysinfo.h>
|
||||
#include <freerdp/server/server-common.h>
|
||||
#include <freerdp/log.h>
|
||||
#define TAG SERVER_TAG("mac")
|
||||
|
||||
AQRecorderState recorderState;
|
||||
|
||||
static void mf_peer_rdpsnd_activated(RdpsndServerContext* context)
|
||||
{
|
||||
OSStatus status;
|
||||
BOOL formatAgreed = FALSE;
|
||||
AUDIO_FORMAT* agreedFormat = nullptr;
|
||||
// we should actually loop through the list of client formats here
|
||||
// and see if we can send the client something that it supports...
|
||||
WLog_DBG(TAG, "Client supports the following %d formats: ", context->num_client_formats);
|
||||
|
||||
int i = 0;
|
||||
for (; i < context->num_client_formats; i++)
|
||||
{
|
||||
/* TODO: improve the way we agree on a format */
|
||||
for (int 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!");
|
||||
formatAgreed = TRUE;
|
||||
agreedFormat = (AUDIO_FORMAT*)&context->server_formats[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (formatAgreed == TRUE)
|
||||
break;
|
||||
}
|
||||
|
||||
if (formatAgreed == FALSE)
|
||||
{
|
||||
WLog_DBG(TAG, "Could not agree on a audio format with the server");
|
||||
return;
|
||||
}
|
||||
|
||||
context->SelectFormat(context, i);
|
||||
context->SetVolume(context, 0x7FFF, 0x7FFF);
|
||||
|
||||
switch (agreedFormat->wFormatTag)
|
||||
{
|
||||
case WAVE_FORMAT_ALAW:
|
||||
recorderState.dataFormat.mFormatID = kAudioFormatDVIIntelIMA;
|
||||
break;
|
||||
|
||||
case WAVE_FORMAT_PCM:
|
||||
recorderState.dataFormat.mFormatID = kAudioFormatLinearPCM;
|
||||
break;
|
||||
|
||||
default:
|
||||
recorderState.dataFormat.mFormatID = kAudioFormatLinearPCM;
|
||||
break;
|
||||
}
|
||||
|
||||
recorderState.dataFormat.mSampleRate = agreedFormat->nSamplesPerSec;
|
||||
recorderState.dataFormat.mFormatFlags =
|
||||
kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
|
||||
recorderState.dataFormat.mBytesPerPacket = 4;
|
||||
recorderState.dataFormat.mFramesPerPacket = 1;
|
||||
recorderState.dataFormat.mBytesPerFrame = 4;
|
||||
recorderState.dataFormat.mChannelsPerFrame = agreedFormat->nChannels;
|
||||
recorderState.dataFormat.mBitsPerChannel = agreedFormat->wBitsPerSample;
|
||||
recorderState.snd_context = context;
|
||||
status =
|
||||
AudioQueueNewInput(&recorderState.dataFormat, mf_peer_rdpsnd_input_callback, &recorderState,
|
||||
nullptr, kCFRunLoopCommonModes, 0, &recorderState.queue);
|
||||
|
||||
if (status != noErr)
|
||||
{
|
||||
WLog_DBG(TAG, "Failed to create a new Audio Queue. Status code: %" PRId32 "", status);
|
||||
}
|
||||
|
||||
UInt32 dataFormatSize = sizeof(recorderState.dataFormat);
|
||||
AudioQueueGetProperty(recorderState.queue, kAudioConverterCurrentInputStreamDescription,
|
||||
&recorderState.dataFormat, &dataFormatSize);
|
||||
mf_rdpsnd_derive_buffer_size(recorderState.queue, &recorderState.dataFormat, 0.05,
|
||||
&recorderState.bufferByteSize);
|
||||
|
||||
for (size_t x = 0; x < SND_NUMBUFFERS; ++x)
|
||||
{
|
||||
AudioQueueAllocateBuffer(recorderState.queue, recorderState.bufferByteSize,
|
||||
&recorderState.buffers[x]);
|
||||
AudioQueueEnqueueBuffer(recorderState.queue, recorderState.buffers[x], 0, nullptr);
|
||||
}
|
||||
|
||||
recorderState.currentPacket = 0;
|
||||
recorderState.isRunning = true;
|
||||
AudioQueueStart(recorderState.queue, nullptr);
|
||||
}
|
||||
|
||||
BOOL mf_peer_rdpsnd_init(mfPeerContext* context)
|
||||
{
|
||||
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 = mf_peer_rdpsnd_activated;
|
||||
context->rdpsnd->Initialize(context->rdpsnd, TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL mf_peer_rdpsnd_stop(void)
|
||||
{
|
||||
recorderState.isRunning = false;
|
||||
AudioQueueStop(recorderState.queue, true);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void mf_peer_rdpsnd_input_callback(void* inUserData, AudioQueueRef inAQ,
|
||||
AudioQueueBufferRef inBuffer, const AudioTimeStamp* inStartTime,
|
||||
UInt32 inNumberPacketDescriptions,
|
||||
const AudioStreamPacketDescription* inPacketDescs)
|
||||
{
|
||||
OSStatus status;
|
||||
AQRecorderState* rState;
|
||||
rState = inUserData;
|
||||
|
||||
if (inNumberPacketDescriptions == 0 && rState->dataFormat.mBytesPerPacket != 0)
|
||||
{
|
||||
inNumberPacketDescriptions =
|
||||
inBuffer->mAudioDataByteSize / rState->dataFormat.mBytesPerPacket;
|
||||
}
|
||||
|
||||
if (rState->isRunning == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rState->snd_context->SendSamples(rState->snd_context, inBuffer->mAudioData,
|
||||
inBuffer->mAudioDataByteSize / 4,
|
||||
(UINT16)(GetTickCount() & 0xffff));
|
||||
status = AudioQueueEnqueueBuffer(rState->queue, inBuffer, 0, nullptr);
|
||||
|
||||
if (status != noErr)
|
||||
{
|
||||
WLog_DBG(TAG, "AudioQueueEnqueueBuffer() returned status = %" PRId32 "", status);
|
||||
}
|
||||
}
|
||||
|
||||
void mf_rdpsnd_derive_buffer_size(AudioQueueRef audioQueue,
|
||||
AudioStreamBasicDescription* ASBDescription, Float64 seconds,
|
||||
UInt32* outBufferSize)
|
||||
{
|
||||
static const int maxBufferSize = 0x50000;
|
||||
int maxPacketSize = ASBDescription->mBytesPerPacket;
|
||||
|
||||
if (maxPacketSize == 0)
|
||||
{
|
||||
UInt32 maxVBRPacketSize = sizeof(maxPacketSize);
|
||||
AudioQueueGetProperty(audioQueue, kAudioQueueProperty_MaximumOutputPacketSize,
|
||||
// in Mac OS X v10.5, instead use
|
||||
// kAudioConverterPropertyMaximumOutputPacketSize
|
||||
&maxPacketSize, &maxVBRPacketSize);
|
||||
}
|
||||
|
||||
Float64 numBytesForTime = ASBDescription->mSampleRate * maxPacketSize * seconds;
|
||||
*outBufferSize = (UInt32)(numBytesForTime < maxBufferSize ? numBytesForTime : maxBufferSize);
|
||||
}
|
||||
58
third_party/FreeRDP/server/Mac/mf_rdpsnd.h
vendored
Normal file
58
third_party/FreeRDP/server/Mac/mf_rdpsnd.h
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Mac OS X 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_MAC_RDPSND_H
|
||||
#define FREERDP_SERVER_MAC_RDPSND_H
|
||||
|
||||
#include <CoreAudio/CoreAudio.h>
|
||||
#include <AudioToolbox/AudioToolbox.h>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/listener.h>
|
||||
#include <freerdp/server/rdpsnd.h>
|
||||
|
||||
#include "mf_types.h"
|
||||
#include "mfreerdp.h"
|
||||
|
||||
void mf_rdpsnd_derive_buffer_size(AudioQueueRef audioQueue,
|
||||
AudioStreamBasicDescription* ASBDescription, Float64 seconds,
|
||||
UInt32* outBufferSize);
|
||||
|
||||
void mf_peer_rdpsnd_input_callback(void* inUserData, AudioQueueRef inAQ,
|
||||
AudioQueueBufferRef inBuffer, const AudioTimeStamp* inStartTime,
|
||||
UInt32 inNumberPacketDescriptions,
|
||||
const AudioStreamPacketDescription* inPacketDescs);
|
||||
|
||||
#define SND_NUMBUFFERS 3
|
||||
typedef struct
|
||||
{
|
||||
AudioStreamBasicDescription dataFormat;
|
||||
AudioQueueRef queue;
|
||||
AudioQueueBufferRef buffers[SND_NUMBUFFERS];
|
||||
AudioFileID audioFile;
|
||||
UInt32 bufferByteSize;
|
||||
SInt64 currentPacket;
|
||||
bool isRunning;
|
||||
RdpsndServerContext* snd_context;
|
||||
} AQRecorderState;
|
||||
|
||||
WINPR_ATTR_NODISCARD BOOL mf_peer_rdpsnd_init(mfPeerContext* context);
|
||||
WINPR_ATTR_NODISCARD BOOL mf_peer_rdpsnd_stop(void);
|
||||
|
||||
#endif /* FREERDP_SERVER_MAC_RDPSND_H */
|
||||
33
third_party/FreeRDP/server/Mac/mf_types.h
vendored
Normal file
33
third_party/FreeRDP/server/Mac/mf_types.h
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Client
|
||||
* FreeRDP Mac OS X Server
|
||||
*
|
||||
* Copyright 2023 Armin Novak <anovak@thincst.com>
|
||||
* Copyright 2023 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_MAC_TYPES_H
|
||||
#define FREERDP_SERVER_MAC_TYPES_H
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
|
||||
typedef struct mf_info mfInfo;
|
||||
typedef struct mf_peer_context mfPeerContext;
|
||||
|
||||
#endif /* FREERDP_SERVER_MAC_TYPES_H */
|
||||
108
third_party/FreeRDP/server/Mac/mfreerdp.c
vendored
Normal file
108
third_party/FreeRDP/server/Mac/mfreerdp.c
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Mac OS X 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <CoreGraphics/CGEvent.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/wtsapi.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/channels/wtsvc.h>
|
||||
#include <freerdp/channels/channels.h>
|
||||
#include <freerdp/server/server-common.h>
|
||||
|
||||
#include "mfreerdp.h"
|
||||
#include "mf_peer.h"
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG SERVER_TAG("mac")
|
||||
|
||||
static void mf_server_main_loop(freerdp_listener* instance)
|
||||
{
|
||||
WINPR_ASSERT(instance);
|
||||
WINPR_ASSERT(instance->GetEventHandles);
|
||||
WINPR_ASSERT(instance->CheckFileDescriptor);
|
||||
|
||||
while (1)
|
||||
{
|
||||
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)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
instance->Close(instance);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
freerdp_server_warn_unmaintained(argc, argv);
|
||||
mf_server_info info = { .key = "server.key", .cert = "server.crt" };
|
||||
|
||||
freerdp_listener* instance;
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi());
|
||||
|
||||
if (!(instance = freerdp_listener_new()))
|
||||
return 1;
|
||||
|
||||
instance->info = &info;
|
||||
instance->PeerAccepted = mf_peer_accepted;
|
||||
|
||||
if (instance->Open(instance, nullptr, 3389))
|
||||
{
|
||||
mf_server_main_loop(instance);
|
||||
}
|
||||
|
||||
freerdp_listener_free(instance);
|
||||
|
||||
return 0;
|
||||
}
|
||||
28
third_party/FreeRDP/server/Mac/mfreerdp.h
vendored
Normal file
28
third_party/FreeRDP/server/Mac/mfreerdp.h
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Mac OS X 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_MAC_FREERDP_H
|
||||
#define FREERDP_SERVER_MAC_FREERDP_H
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/listener.h>
|
||||
#include <freerdp/codec/rfx.h>
|
||||
|
||||
#endif /* FREERDP_SERVER_MAC_FREERDP_H */
|
||||
Reference in New Issue
Block a user