Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions

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

View File

@@ -0,0 +1,3 @@
set(FREERDP_SERVER_NAME "mfreerdp-server")
set(FREERDP_SERVER_PLATFORM "X11")
set(FREERDP_SERVER_VENDOR "FreeRDP")

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

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

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

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

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

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

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

View File

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

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

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

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

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

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

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

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

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