Merge pull request #986 from C-o-r-E/master
Server improvements on OS X and Windows
This commit is contained in:
commit
abc3386f8a
@ -3,6 +3,7 @@
|
||||
#
|
||||
# Copyright 2012 Laxmikant Rashinkar <LK.Rashinkar@gmail.com>
|
||||
# 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.
|
||||
@ -18,6 +19,10 @@
|
||||
|
||||
define_channel_client_subsystem("rdpsnd" "mac" "")
|
||||
|
||||
FIND_LIBRARY(CORE_AUDIO CoreAudio)
|
||||
FIND_LIBRARY(AUDIO_TOOL AudioToolbox)
|
||||
FIND_LIBRARY(CORE_FOUNDATION CoreFoundation)
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
rdpsnd_mac.c)
|
||||
|
||||
@ -33,8 +38,10 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MODULE freerdp
|
||||
MODULES freerdp-utils)
|
||||
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${MAC_AUDIOTOOLBOX_LIBRARY_PATH})
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${MAC_COREFOUNDATION_LIBRARY_PATH})
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS}
|
||||
${AUDIO_TOOL}
|
||||
${CORE_AUDIO}
|
||||
${CORE_FOUNDATION})
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
|
||||
|
@ -97,16 +97,17 @@ static void rdpsnd_audio_open(rdpsndDevicePlugin* device, rdpsndFormat* format,
|
||||
aq_plugin_p->data_format.mChannelsPerFrame = 2;
|
||||
aq_plugin_p->data_format.mBitsPerChannel = 16;
|
||||
|
||||
rv = AudioQueueNewOutput(&aq_plugin_p->data_format, // audio stream basic desc
|
||||
aq_playback_cb, // callback when more data is required
|
||||
aq_plugin_p, // data to pass to callback
|
||||
CFRunLoopGetCurrent(), // The current run loop, and the one on
|
||||
// which the audio queue playback callback
|
||||
// will be invoked
|
||||
kCFRunLoopCommonModes, // run loop modes in which callbacks can
|
||||
// be invoked
|
||||
0, // flags - reserved
|
||||
&aq_plugin_p->aq_ref
|
||||
rv = AudioQueueNewOutput(
|
||||
&aq_plugin_p->data_format, // audio stream basic desc
|
||||
aq_playback_cb, // callback when more data is required
|
||||
aq_plugin_p, // data to pass to callback
|
||||
CFRunLoopGetCurrent(), // The current run loop, and the one on
|
||||
// which the audio queue playback callback
|
||||
// will be invoked
|
||||
kCFRunLoopCommonModes, // run loop modes in which callbacks can
|
||||
// be invoked
|
||||
0, // flags - reserved
|
||||
&aq_plugin_p->aq_ref
|
||||
);
|
||||
if (rv != 0) {
|
||||
printf("rdpsnd_audio_open: AudioQueueNewOutput() failed with error %d\n", rv);
|
||||
@ -204,6 +205,8 @@ static void aq_playback_cb(void* user_data, AudioQueueRef aq_ref, AudioQueueBuff
|
||||
|
||||
int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints)
|
||||
{
|
||||
printf("freerdp_rdpsnd_client_subsystem_entry()\n\n");
|
||||
|
||||
ADDIN_ARGV* args;
|
||||
rdpsndAudioQPlugin* aqPlugin;
|
||||
|
||||
|
@ -40,6 +40,7 @@
|
||||
#cmakedefine WITH_NATIVE_SSPI
|
||||
#cmakedefine WITH_JPEG
|
||||
#cmakedefine WITH_WIN8
|
||||
#cmakedefine WITH_RDPSND_DSOUND
|
||||
|
||||
/* Plugins */
|
||||
#cmakedefine STATIC_CHANNELS
|
||||
|
@ -60,15 +60,15 @@ void mf_peer_audin_init(mfPeerContext* context)
|
||||
{
|
||||
context->audin = audin_server_context_new(context->vcm);
|
||||
context->audin->data = context;
|
||||
|
||||
|
||||
context->audin->server_formats = audio_formats;
|
||||
context->audin->num_server_formats = sizeof(audio_formats) / sizeof(audio_formats[0]);
|
||||
|
||||
|
||||
context->audin->dst_format.wFormatTag = 1;
|
||||
context->audin->dst_format.nChannels = 2;
|
||||
context->audin->dst_format.nSamplesPerSec = 44100;
|
||||
context->audin->dst_format.wBitsPerSample = 16;
|
||||
|
||||
|
||||
context->audin->Opening = mf_peer_audin_opening;
|
||||
context->audin->OpenResult = mf_peer_audin_open_result;
|
||||
context->audin->ReceiveSamples = mf_peer_audin_receive_samples;
|
||||
|
@ -35,21 +35,21 @@ int mf_is_event_set(mfEventQueue* event_queue)
|
||||
fd_set rfds;
|
||||
int num_set;
|
||||
struct timeval time;
|
||||
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(event_queue->pipe_fd[0], &rfds);
|
||||
memset(&time, 0, sizeof(time));
|
||||
num_set = select(event_queue->pipe_fd[0] + 1, &rfds, 0, 0, &time);
|
||||
|
||||
|
||||
return (num_set == 1);
|
||||
}
|
||||
|
||||
void mf_signal_event(mfEventQueue* event_queue)
|
||||
{
|
||||
int length;
|
||||
|
||||
|
||||
length = write(event_queue->pipe_fd[1], "sig", 4);
|
||||
|
||||
|
||||
if (length != 4)
|
||||
printf("mf_signal_event: error\n");
|
||||
}
|
||||
@ -57,9 +57,9 @@ void mf_signal_event(mfEventQueue* event_queue)
|
||||
void mf_set_event(mfEventQueue* event_queue)
|
||||
{
|
||||
int length;
|
||||
|
||||
|
||||
length = write(event_queue->pipe_fd[1], "sig", 4);
|
||||
|
||||
|
||||
if (length != 4)
|
||||
printf("mf_set_event: error\n");
|
||||
}
|
||||
@ -67,11 +67,11 @@ void mf_set_event(mfEventQueue* event_queue)
|
||||
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)
|
||||
printf("mf_clear_event: error\n");
|
||||
}
|
||||
@ -80,9 +80,9 @@ void mf_clear_events(mfEventQueue* event_queue)
|
||||
void mf_clear_event(mfEventQueue* event_queue)
|
||||
{
|
||||
int length;
|
||||
|
||||
|
||||
length = read(event_queue->pipe_fd[0], &length, 4);
|
||||
|
||||
|
||||
if (length != 4)
|
||||
printf("mf_clear_event: error\n");
|
||||
}
|
||||
@ -90,62 +90,62 @@ void mf_clear_event(mfEventQueue* event_queue)
|
||||
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 = NULL;
|
||||
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 NULL;
|
||||
|
||||
|
||||
/* 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 != NULL)
|
||||
{
|
||||
event_region->x = x;
|
||||
@ -153,7 +153,7 @@ mfEventRegion* mf_event_region_new(int x, int y, int width, int height)
|
||||
event_region->width = width;
|
||||
event_region->height = height;
|
||||
}
|
||||
|
||||
|
||||
return event_region;
|
||||
}
|
||||
|
||||
@ -177,22 +177,22 @@ void mf_event_free(mfEvent* event)
|
||||
mfEventQueue* mf_event_queue_new()
|
||||
{
|
||||
mfEventQueue* event_queue = malloc(sizeof(mfEventQueue));
|
||||
|
||||
|
||||
if (event_queue != NULL)
|
||||
{
|
||||
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)
|
||||
printf("mf_event_queue_new: pipe failed\n");
|
||||
|
||||
|
||||
pthread_mutex_init(&(event_queue->mutex), NULL);
|
||||
}
|
||||
|
||||
|
||||
return event_queue;
|
||||
}
|
||||
|
||||
@ -203,12 +203,12 @@ void mf_event_queue_free(mfEventQueue* event_queue)
|
||||
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));
|
||||
}
|
@ -52,7 +52,7 @@ struct mf_event_queue
|
||||
struct mf_event_region
|
||||
{
|
||||
int type;
|
||||
|
||||
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
|
@ -1,21 +1,21 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@ -34,116 +34,116 @@ static mfInfo* mfInfoInstance = NULL;
|
||||
|
||||
int mf_info_lock(mfInfo* mfi)
|
||||
{
|
||||
|
||||
int status = pthread_mutex_lock(&mfi->mutex);
|
||||
|
||||
switch (status) {
|
||||
case 0:
|
||||
return TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("mf_info_lock failed with %#X\n", status);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
int status = pthread_mutex_lock(&mfi->mutex);
|
||||
|
||||
switch (status) {
|
||||
case 0:
|
||||
return TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("mf_info_lock failed with %#X\n", status);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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:
|
||||
printf("mf_info_try_lock failed with %#X\n", status);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
int status = pthread_mutex_trylock(&mfi->mutex);
|
||||
|
||||
switch (status) {
|
||||
case 0:
|
||||
return TRUE;
|
||||
break;
|
||||
|
||||
case EBUSY:
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("mf_info_try_lock failed with %#X\n", status);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int mf_info_unlock(mfInfo* mfi)
|
||||
{
|
||||
int status = pthread_mutex_unlock(&mfi->mutex);
|
||||
|
||||
switch (status) {
|
||||
case 0:
|
||||
return TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("mf_info_unlock failed with %#X\n", status);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
int status = pthread_mutex_unlock(&mfi->mutex);
|
||||
|
||||
switch (status) {
|
||||
case 0:
|
||||
return TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("mf_info_unlock failed with %#X\n", status);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mfInfo* mf_info_init()
|
||||
{
|
||||
mfInfo* mfi;
|
||||
|
||||
mfi = (mfInfo*) malloc(sizeof(mfInfo));
|
||||
memset(mfi, 0, sizeof(mfInfo));
|
||||
|
||||
|
||||
mfi = (mfInfo*) malloc(sizeof(mfInfo));
|
||||
memset(mfi, 0, sizeof(mfInfo));
|
||||
|
||||
|
||||
if (mfi != NULL)
|
||||
{
|
||||
/* HKEY hKey;
|
||||
LONG status;
|
||||
DWORD dwType;
|
||||
DWORD dwSize;
|
||||
DWORD dwValue;
|
||||
*/
|
||||
|
||||
int mutexInitStatus = pthread_mutex_init(&mfi->mutex, NULL);
|
||||
|
||||
/* HKEY hKey;
|
||||
LONG status;
|
||||
DWORD dwType;
|
||||
DWORD dwSize;
|
||||
DWORD dwValue;
|
||||
*/
|
||||
|
||||
int mutexInitStatus = pthread_mutex_init(&mfi->mutex, NULL);
|
||||
|
||||
if (mutexInitStatus != 0)
|
||||
{
|
||||
printf(_T("CreateMutex error: %#X\n"), mutexInitStatus);
|
||||
}
|
||||
|
||||
|
||||
mfi->peers = (freerdp_peer**) malloc(sizeof(freerdp_peer*) * MF_INFO_MAXPEERS);
|
||||
memset(mfi->peers, 0, sizeof(freerdp_peer*) * MF_INFO_MAXPEERS);
|
||||
|
||||
|
||||
//Set FPS
|
||||
mfi->framesPerSecond = MF_INFO_DEFAULT_FPS;
|
||||
|
||||
|
||||
/*status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
|
||||
if (status == ERROR_SUCCESS)
|
||||
{
|
||||
if (RegQueryValueEx(hKey, _T("FramesPerSecond"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
mfi->framesPerSecond = dwValue;
|
||||
}
|
||||
RegCloseKey(hKey);*/
|
||||
|
||||
if (status == ERROR_SUCCESS)
|
||||
{
|
||||
if (RegQueryValueEx(hKey, _T("FramesPerSecond"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
mfi->framesPerSecond = dwValue;
|
||||
}
|
||||
RegCloseKey(hKey);*/
|
||||
|
||||
//Set input toggle
|
||||
mfi->input_disabled = FALSE;
|
||||
|
||||
|
||||
/*status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
|
||||
if (status == ERROR_SUCCESS)
|
||||
{
|
||||
if (RegQueryValueEx(hKey, _T("DisableInput"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
{
|
||||
if (dwValue != 0)
|
||||
mfi->input_disabled = TRUE;
|
||||
}
|
||||
}
|
||||
RegCloseKey(hKey);*/
|
||||
|
||||
if (status == ERROR_SUCCESS)
|
||||
{
|
||||
if (RegQueryValueEx(hKey, _T("DisableInput"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
{
|
||||
if (dwValue != 0)
|
||||
mfi->input_disabled = TRUE;
|
||||
}
|
||||
}
|
||||
RegCloseKey(hKey);*/
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return mfi;
|
||||
}
|
||||
|
||||
@ -151,7 +151,7 @@ mfInfo* mf_info_get_instance()
|
||||
{
|
||||
if (mfInfoInstance == NULL)
|
||||
mfInfoInstance = mf_info_init();
|
||||
|
||||
|
||||
return mfInfoInstance;
|
||||
}
|
||||
|
||||
@ -163,27 +163,28 @@ void mf_info_peer_register(mfInfo* mfi, mfPeerContext* context)
|
||||
int peerId;
|
||||
if (mfi->peerCount == MF_INFO_MAXPEERS)
|
||||
{
|
||||
printf("TODO: socketClose on OS X\n");
|
||||
printf("TODO: socketClose on OS X\n");
|
||||
//context->socketClose = TRUE;
|
||||
mf_info_unlock(mfi);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
context->info = mfi;
|
||||
|
||||
//get the offset of the top left corner of selected screen
|
||||
//EnumDisplayMonitors(NULL, NULL, mf_info_monEnumCB, 0);
|
||||
//_IDcount = 0;
|
||||
|
||||
//initialize screen capture
|
||||
|
||||
//initialize screen capture
|
||||
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();
|
||||
}
|
||||
|
||||
{
|
||||
mf_mlion_display_info(&mfi->servscreen_width, &mfi->servscreen_height, &mfi->scale);
|
||||
mf_mlion_screen_updates_init();
|
||||
mf_mlion_start_getting_screen_updates();
|
||||
}
|
||||
|
||||
//look trhough the array of peers until an empty slot
|
||||
peerId = NULL;
|
||||
for(i=0; i<MF_INFO_MAXPEERS; ++i)
|
||||
{
|
||||
//empty index will be our peer id
|
||||
@ -193,14 +194,14 @@ void mf_info_peer_register(mfInfo* mfi, mfPeerContext* context)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mfi->peers[peerId] = ((rdpContext*) context)->peer;
|
||||
mfi->peers[peerId]->pId = peerId;
|
||||
mfi->peerCount++;
|
||||
printf("Registering Peer: id=%d #=%d\n", peerId, mfi->peerCount);
|
||||
|
||||
//printf("Registering Peer: id=%d #=%d\n", peerId, mfi->peerCount);
|
||||
|
||||
mf_info_unlock(mfi);
|
||||
|
||||
|
||||
//mfreerdp_server_peer_callback_event(peerId, MF_SRV_CALLBACK_EVENT_CONNECT);
|
||||
}
|
||||
}
|
||||
@ -210,20 +211,20 @@ 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] = NULL;
|
||||
mfi->peerCount--;
|
||||
|
||||
printf("Unregistering Peer: id=%d, #=%d\n", peerId, mfi->peerCount);
|
||||
|
||||
//screen capture cleanup
|
||||
|
||||
//printf("Unregistering Peer: id=%d, #=%d\n", peerId, mfi->peerCount);
|
||||
|
||||
//screen capture cleanup
|
||||
if (mfi->peerCount == 0)
|
||||
{
|
||||
mf_mlion_stop_getting_screen_updates();
|
||||
}
|
||||
{
|
||||
mf_mlion_stop_getting_screen_updates();
|
||||
}
|
||||
mf_info_unlock(mfi);
|
||||
|
||||
|
||||
//mfreerdp_server_peer_callback_event(peerId, MF_SRV_CALLBACK_EVENT_DISCONNECT);
|
||||
}
|
||||
}
|
||||
@ -232,77 +233,77 @@ BOOL mf_info_have_updates(mfInfo* mfi)
|
||||
{
|
||||
if(mfi->framesWaiting == 0)
|
||||
return FALSE;
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void mf_info_update_changes(mfInfo* mfi)
|
||||
{
|
||||
/*#ifdef WITH_WIN8
|
||||
mf_dxgi_nextFrame(mfi, mfi->framesPerSecond * 1000);
|
||||
#else
|
||||
GETCHANGESBUF* buf;
|
||||
|
||||
buf = (GETCHANGESBUF*) mfi->changeBuffer;
|
||||
mfi->nextUpdate = buf->buffer->counter;
|
||||
#endif*/
|
||||
/*#ifdef WITH_WIN8
|
||||
mf_dxgi_nextFrame(mfi, mfi->framesPerSecond * 1000);
|
||||
#else
|
||||
GETCHANGESBUF* buf;
|
||||
|
||||
buf = (GETCHANGESBUF*) mfi->changeBuffer;
|
||||
mfi->nextUpdate = buf->buffer->counter;
|
||||
#endif*/
|
||||
}
|
||||
|
||||
void mf_info_find_invalid_region(mfInfo* mfi)
|
||||
{
|
||||
mf_mlion_get_dirty_region(&mfi->invalid);
|
||||
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;
|
||||
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.height = mfi->servscreen_width;
|
||||
mfi->invalid.x = 0;
|
||||
mfi->invalid.y = 0;
|
||||
mfi->invalid.height = mfi->servscreen_height;
|
||||
mfi->invalid.height = mfi->servscreen_width;
|
||||
}
|
||||
|
||||
BOOL mf_info_have_invalid_region(mfInfo* mfi)
|
||||
{
|
||||
if (mfi->invalid.width * mfi->invalid.height == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
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);
|
||||
|
||||
*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);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
BOOL CALLBACK mf_info_monEnumCB(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
|
||||
{
|
||||
mfInfo * mfi;
|
||||
|
||||
mfi = mf_info_get_instance();
|
||||
|
||||
if(_IDcount == mfi->screenID)
|
||||
{
|
||||
mfi->servscreen_xoffset = lprcMonitor->left;
|
||||
mfi->servscreen_yoffset = lprcMonitor->top;
|
||||
}
|
||||
|
||||
_IDcount++;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
*/
|
||||
BOOL CALLBACK mf_info_monEnumCB(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
|
||||
{
|
||||
mfInfo * mfi;
|
||||
|
||||
mfi = mf_info_get_instance();
|
||||
|
||||
if(_IDcount == mfi->screenID)
|
||||
{
|
||||
mfi->servscreen_xoffset = lprcMonitor->left;
|
||||
mfi->servscreen_yoffset = lprcMonitor->top;
|
||||
}
|
||||
|
||||
_IDcount++;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
*/
|
||||
|
@ -48,32 +48,32 @@ typedef struct mf_peer_context mfPeerContext;
|
||||
struct mf_peer_context
|
||||
{
|
||||
rdpContext _p;
|
||||
|
||||
mfInfo* info;
|
||||
|
||||
mfInfo* info;
|
||||
STREAM* s;
|
||||
BOOL activated;
|
||||
UINT32 frame_id;
|
||||
BOOL audin_open;
|
||||
RFX_CONTEXT* rfx_context;
|
||||
NSC_CONTEXT* nsc_context;
|
||||
|
||||
//#ifdef WITH_SERVER_CHANNELS
|
||||
|
||||
//#ifdef WITH_SERVER_CHANNELS
|
||||
WTSVirtualChannelManager* vcm;
|
||||
//#endif
|
||||
//#ifdef CHANNEL_AUDIN_SERVER
|
||||
//#endif
|
||||
//#ifdef CHANNEL_AUDIN_SERVER
|
||||
audin_server_context* audin;
|
||||
//#endif
|
||||
|
||||
//#ifdef CHANNEL_RDPSND_SERVER
|
||||
//#endif
|
||||
|
||||
//#ifdef CHANNEL_RDPSND_SERVER
|
||||
rdpsnd_server_context* rdpsnd;
|
||||
//#endif
|
||||
//#endif
|
||||
};
|
||||
|
||||
|
||||
struct mf_info
|
||||
{
|
||||
//STREAM* s;
|
||||
|
||||
|
||||
//screen and monitor info
|
||||
UINT32 screenID;
|
||||
UINT32 virtscreen_width;
|
||||
@ -82,7 +82,7 @@ struct mf_info
|
||||
UINT32 servscreen_height;
|
||||
UINT32 servscreen_xoffset;
|
||||
UINT32 servscreen_yoffset;
|
||||
|
||||
|
||||
//int frame_idx;
|
||||
int bitsPerPixel;
|
||||
//HDC driverDC;
|
||||
@ -95,11 +95,11 @@ struct mf_info
|
||||
freerdp_peer** peers;
|
||||
//BOOL mirrorDriverActive;
|
||||
unsigned int framesWaiting;
|
||||
UINT32 scale;
|
||||
|
||||
UINT32 scale;
|
||||
|
||||
//HANDLE snd_mutex;
|
||||
//BOOL snd_stop;
|
||||
|
||||
|
||||
RFX_RECT invalid;
|
||||
pthread_mutex_t mutex;
|
||||
//BOOL updatePending;
|
||||
@ -110,7 +110,7 @@ struct mf_info
|
||||
//unsigned long lastUpdate;
|
||||
//unsigned long nextUpdate;
|
||||
//SURFACE_BITS_COMMAND cmd;
|
||||
|
||||
|
||||
BOOL input_disabled;
|
||||
BOOL force_all_disconnect;
|
||||
};
|
||||
|
@ -34,273 +34,241 @@ CGDisplayStreamUpdateRef lastUpdate = NULL;
|
||||
|
||||
BYTE* localBuf = NULL;
|
||||
|
||||
//CVPixelBufferRef pxbuffer = NULL;
|
||||
//void *baseAddress = NULL;
|
||||
|
||||
//CGContextRef bitmapcontext = NULL;
|
||||
|
||||
//CGImageRef image = NULL;
|
||||
|
||||
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, NULL);
|
||||
//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, NULL);
|
||||
|
||||
ready = FALSE;
|
||||
dispatch_semaphore_signal(data_sem);
|
||||
}
|
||||
|
||||
if (status != kCGDisplayStreamFrameStatusFrameComplete)
|
||||
{
|
||||
//unhandled
|
||||
switch(status)
|
||||
{
|
||||
case kCGDisplayStreamFrameStatusFrameIdle:
|
||||
printf("kCGDisplayStreamFrameStatusFrameIdle\n");
|
||||
break;
|
||||
|
||||
case kCGDisplayStreamFrameStatusStopped:
|
||||
printf("kCGDisplayStreamFrameStatusStopped\n");
|
||||
break;
|
||||
|
||||
case kCGDisplayStreamFrameStatusFrameBlank:
|
||||
printf("kCGDisplayStreamFrameStatusFrameBlank\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Unhandled Frame Status!!!\n");
|
||||
|
||||
}
|
||||
}
|
||||
else if (lastUpdate == NULL)
|
||||
{
|
||||
CFRetain(updateRef);
|
||||
lastUpdate = updateRef;
|
||||
}
|
||||
else
|
||||
{
|
||||
CGDisplayStreamUpdateRef tmpRef;
|
||||
tmpRef = lastUpdate;
|
||||
lastUpdate = CGDisplayStreamUpdateCreateMergedUpdate(tmpRef, updateRef);
|
||||
CFRelease(tmpRef);
|
||||
}
|
||||
|
||||
dispatch_semaphore_signal(region_sem);
|
||||
|
||||
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, NULL);
|
||||
//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, NULL);
|
||||
|
||||
ready = FALSE;
|
||||
dispatch_semaphore_signal(data_sem);
|
||||
}
|
||||
|
||||
if (status != kCGDisplayStreamFrameStatusFrameComplete)
|
||||
{
|
||||
//unhandled
|
||||
switch(status)
|
||||
{
|
||||
case kCGDisplayStreamFrameStatusFrameIdle:
|
||||
printf("kCGDisplayStreamFrameStatusFrameIdle\n");
|
||||
break;
|
||||
|
||||
case kCGDisplayStreamFrameStatusStopped:
|
||||
//we dont need to clean up
|
||||
//printf("kCGDisplayStreamFrameStatusStopped\n");
|
||||
break;
|
||||
|
||||
case kCGDisplayStreamFrameStatusFrameBlank:
|
||||
printf("kCGDisplayStreamFrameStatusFrameBlank\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Unhandled Frame Status!!!\n");
|
||||
|
||||
}
|
||||
}
|
||||
else if (lastUpdate == NULL)
|
||||
{
|
||||
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;
|
||||
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()
|
||||
{
|
||||
printf("mf_mlion_screen_updates_init()\n");
|
||||
CGDirectDisplayID display_id;
|
||||
|
||||
display_id = CGMainDisplayID();
|
||||
|
||||
screen_update_q = dispatch_queue_create("mfreerdp.server.screenUpdate", NULL);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
stream = CGDisplayStreamCreateWithDispatchQueue(display_id,
|
||||
pixelWidth,
|
||||
pixelHeight,
|
||||
'BGRA',
|
||||
NULL,
|
||||
screen_update_q,
|
||||
streamHandler);
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
CGDirectDisplayID display_id;
|
||||
|
||||
display_id = CGMainDisplayID();
|
||||
|
||||
screen_update_q = dispatch_queue_create("mfreerdp.server.screenUpdate", NULL);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
stream = CGDisplayStreamCreateWithDispatchQueue(display_id,
|
||||
pixelWidth,
|
||||
pixelHeight,
|
||||
'BGRA',
|
||||
NULL,
|
||||
screen_update_q,
|
||||
streamHandler);
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int mf_mlion_start_getting_screen_updates()
|
||||
{
|
||||
CGError err;
|
||||
|
||||
err = CGDisplayStreamStart(stream);
|
||||
if(err != kCGErrorSuccess)
|
||||
{
|
||||
printf("Failed to start displaystream!! err = %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
CGError err;
|
||||
|
||||
err = CGDisplayStreamStart(stream);
|
||||
if(err != kCGErrorSuccess)
|
||||
{
|
||||
printf("Failed to start displaystream!! err = %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
int mf_mlion_stop_getting_screen_updates()
|
||||
{
|
||||
CGError err;
|
||||
|
||||
err = CGDisplayStreamStop(stream);
|
||||
if(err != kCGErrorSuccess)
|
||||
{
|
||||
printf("Failed to stop displaystream!! err = %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
CGError err;
|
||||
|
||||
err = CGDisplayStreamStop(stream);
|
||||
if(err != kCGErrorSuccess)
|
||||
{
|
||||
printf("Failed to stop displaystream!! err = %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mf_mlion_get_dirty_region(RFX_RECT* invalid)
|
||||
{
|
||||
dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
|
||||
|
||||
if (lastUpdate != NULL)
|
||||
{
|
||||
mf_mlion_peek_dirty_region(invalid);
|
||||
|
||||
//CFRelease(lastUpdate);
|
||||
|
||||
//lastUpdate = NULL;
|
||||
|
||||
}
|
||||
|
||||
|
||||
dispatch_semaphore_signal(region_sem);
|
||||
|
||||
return 0;
|
||||
dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
|
||||
|
||||
if (lastUpdate != NULL)
|
||||
{
|
||||
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);
|
||||
|
||||
//printf("\trectangles: %zd\n", num_rects);
|
||||
|
||||
if (num_rects == 0) {
|
||||
//dispatch_semaphore_signal(region_sem);
|
||||
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;
|
||||
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 = NULL;
|
||||
|
||||
dispatch_semaphore_signal(region_sem);
|
||||
|
||||
|
||||
return 0;
|
||||
dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
|
||||
|
||||
CFRelease(lastUpdate);
|
||||
lastUpdate = NULL;
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
if (image != NULL) {
|
||||
CGImageRelease(image);
|
||||
}
|
||||
image = CGDisplayCreateImageForRect(
|
||||
kCGDirectMainDisplay,
|
||||
CGRectMake(x, y, width, height) );
|
||||
|
||||
CGContextDrawImage(
|
||||
bitmapcontext,
|
||||
CGRectMake(0, 1800 - height, width, height),
|
||||
image);
|
||||
|
||||
*pxData = baseAddress;
|
||||
|
||||
*/
|
||||
|
||||
return 0;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1,21 +1,21 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
@ -61,151 +61,136 @@ 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;
|
||||
}
|
||||
|
||||
BOOL mf_peer_check_fds(freerdp_peer* client)
|
||||
{
|
||||
mfPeerContext* context = (mfPeerContext*) client->context;
|
||||
mfPeerContext* context = (mfPeerContext*) client->context;
|
||||
mfEvent* event;
|
||||
//HGDI_RGN invalid_region;
|
||||
|
||||
|
||||
if (context->activated == FALSE)
|
||||
return TRUE;
|
||||
|
||||
|
||||
event = mf_event_peek(info_event_queue);
|
||||
|
||||
|
||||
if (event != NULL)
|
||||
{
|
||||
if (event->type == MF_EVENT_TYPE_REGION)
|
||||
{
|
||||
printf("unhandled event\n");
|
||||
/*mfEventRegion* region = (mfEventRegion*) mf_event_pop(info_event_queue);
|
||||
gdi_InvalidateRegion(xfp->hdc, region->x, region->y, region->width, region->height);
|
||||
xf_event_region_free(region);*/
|
||||
printf("unhandled event\n");
|
||||
}
|
||||
else if (event->type == MF_EVENT_TYPE_FRAME_TICK)
|
||||
{
|
||||
event = mf_event_pop(info_event_queue);
|
||||
|
||||
mf_peer_rfx_update(client);
|
||||
|
||||
mf_peer_rfx_update(client);
|
||||
|
||||
mf_event_free(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
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 = NULL;
|
||||
|
||||
mf_info_getScreenData(mfi, &width, &height, &dataBits, &pitch);
|
||||
|
||||
mf_info_clear_invalid_region(mfi);
|
||||
|
||||
//encode
|
||||
|
||||
STREAM* s;
|
||||
//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 = NULL;
|
||||
|
||||
mf_info_getScreenData(mfi, &width, &height, &dataBits, &pitch);
|
||||
|
||||
mf_info_clear_invalid_region(mfi);
|
||||
|
||||
//encode
|
||||
|
||||
STREAM* s;
|
||||
RFX_RECT rect;
|
||||
rdpUpdate* update;
|
||||
mfPeerContext* mfp;
|
||||
SURFACE_BITS_COMMAND* cmd;
|
||||
|
||||
|
||||
update = client->update;
|
||||
mfp = (mfPeerContext*) client->context;
|
||||
cmd = &update->surface_bits_command;
|
||||
|
||||
|
||||
s = mfp->s;
|
||||
stream_clear(s);
|
||||
|
||||
|
||||
s = mfp->s;
|
||||
stream_clear(s);
|
||||
stream_set_pos(s, 0);
|
||||
|
||||
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;
|
||||
|
||||
mfp->rfx_context->width = mfi->servscreen_width;
|
||||
mfp->rfx_context->height = mfi->servscreen_height;
|
||||
|
||||
rfx_compose_message(mfp->rfx_context, s, &rect, 1,
|
||||
(BYTE*) dataBits, rect.width, rect.height, pitch);
|
||||
|
||||
cmd->destLeft = x;
|
||||
cmd->destTop = y;
|
||||
cmd->destRight = x + rect.width;
|
||||
cmd->destBottom = y + rect.height;
|
||||
|
||||
|
||||
|
||||
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;
|
||||
|
||||
mfp->rfx_context->width = mfi->servscreen_width;
|
||||
mfp->rfx_context->height = mfi->servscreen_height;
|
||||
|
||||
rfx_compose_message(mfp->rfx_context, s, &rect, 1,
|
||||
(BYTE*) dataBits, rect.width, rect.height, pitch);
|
||||
|
||||
cmd->destLeft = x;
|
||||
cmd->destTop = y;
|
||||
cmd->destRight = x + rect.width;
|
||||
cmd->destBottom = y + rect.height;
|
||||
|
||||
|
||||
cmd->bpp = 32;
|
||||
cmd->codecID = 3;
|
||||
cmd->width = rect.width;
|
||||
cmd->height = rect.height;
|
||||
cmd->bitmapDataLength = stream_get_length(s);
|
||||
cmd->bitmapData = stream_get_head(s);
|
||||
|
||||
//send
|
||||
|
||||
update->SurfaceBits(update->context, cmd);
|
||||
|
||||
//clean up
|
||||
|
||||
// note: need to stop getting new dirty rects until here
|
||||
|
||||
|
||||
/*
|
||||
CGColorSpaceRelease(rgbColorSpace);
|
||||
CGImageRelease(image);
|
||||
CGContextRelease(context);
|
||||
|
||||
CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
|
||||
CVPixelBufferRelease(pxbuffer);
|
||||
*/
|
||||
|
||||
//send
|
||||
|
||||
update->SurfaceBits(update->context, cmd);
|
||||
|
||||
//clean up... maybe?
|
||||
|
||||
}
|
||||
|
||||
/* Called when we have a new peer connecting */
|
||||
void mf_peer_context_new(freerdp_peer* client, mfPeerContext* context)
|
||||
{
|
||||
context->info = mf_info_get_instance();
|
||||
context->info = mf_info_get_instance();
|
||||
context->rfx_context = rfx_context_new();
|
||||
context->rfx_context->mode = RLGR3;
|
||||
context->rfx_context->width = client->settings->DesktopWidth;
|
||||
context->rfx_context->height = client->settings->DesktopHeight;
|
||||
rfx_context_set_pixel_format(context->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8);
|
||||
rfx_context_set_cpu_opt(context->rfx_context, CPU_SSE2);
|
||||
|
||||
rfx_context_set_cpu_opt(context->rfx_context, CPU_SSE2);
|
||||
|
||||
//context->nsc_context = nsc_context_new();
|
||||
//nsc_context_set_pixel_format(context->nsc_context, RDP_PIXEL_FORMAT_B8G8R8A8);
|
||||
|
||||
|
||||
context->s = stream_new(0xFFFF);
|
||||
|
||||
//#ifdef WITH_SERVER_CHANNELS
|
||||
|
||||
//#ifdef WITH_SERVER_CHANNELS
|
||||
context->vcm = WTSCreateVirtualChannelManager(client);
|
||||
//#endif
|
||||
|
||||
mf_info_peer_register(context->info, context);
|
||||
//#endif
|
||||
|
||||
mf_info_peer_register(context->info, context);
|
||||
}
|
||||
|
||||
|
||||
@ -214,29 +199,29 @@ void mf_peer_context_free(freerdp_peer* client, mfPeerContext* context)
|
||||
{
|
||||
if (context)
|
||||
{
|
||||
mf_info_peer_unregister(context->info, context);
|
||||
|
||||
dispatch_suspend(info_timer);
|
||||
|
||||
mf_info_peer_unregister(context->info, context);
|
||||
|
||||
dispatch_suspend(info_timer);
|
||||
|
||||
stream_free(context->s);
|
||||
|
||||
|
||||
rfx_context_free(context->rfx_context);
|
||||
//nsc_context_free(context->nsc_context);
|
||||
|
||||
|
||||
#ifdef CHANNEL_AUDIN_SERVER
|
||||
if (context->audin)
|
||||
audin_server_context_free(context->audin);
|
||||
#endif
|
||||
|
||||
//#ifdef CHANNEL_RDPSND_SERVER
|
||||
mf_peer_rdpsnd_stop();
|
||||
|
||||
//#ifdef CHANNEL_RDPSND_SERVER
|
||||
mf_peer_rdpsnd_stop();
|
||||
if (context->rdpsnd)
|
||||
rdpsnd_server_context_free(context->rdpsnd);
|
||||
//#endif
|
||||
|
||||
//#ifdef WITH_SERVER_CHANNELS
|
||||
//#endif
|
||||
|
||||
//#ifdef WITH_SERVER_CHANNELS
|
||||
WTSDestroyVirtualChannelManager(context->vcm);
|
||||
//#endif
|
||||
//#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,86 +232,86 @@ void mf_peer_init(freerdp_peer* client)
|
||||
client->ContextNew = (psPeerContextNew) mf_peer_context_new;
|
||||
client->ContextFree = (psPeerContextFree) mf_peer_context_free;
|
||||
freerdp_peer_context_new(client);
|
||||
|
||||
info_event_queue = mf_event_queue_new();
|
||||
|
||||
info_queue = dispatch_queue_create("testing.101", DISPATCH_QUEUE_SERIAL);
|
||||
info_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, info_queue);
|
||||
|
||||
if(info_timer)
|
||||
{
|
||||
//printf("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, ^{
|
||||
//printf("dispatch\n");
|
||||
mfEvent* event = mf_event_new(MF_EVENT_TYPE_FRAME_TICK);
|
||||
mf_event_push(info_event_queue, (mfEvent*) event);}
|
||||
);
|
||||
dispatch_resume(info_timer);
|
||||
}
|
||||
|
||||
info_event_queue = mf_event_queue_new();
|
||||
|
||||
info_queue = dispatch_queue_create("testing.101", DISPATCH_QUEUE_SERIAL);
|
||||
info_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, info_queue);
|
||||
|
||||
if(info_timer)
|
||||
{
|
||||
//printf("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, ^{
|
||||
//printf("dispatch\n");
|
||||
mfEvent* event = mf_event_new(MF_EVENT_TYPE_FRAME_TICK);
|
||||
mf_event_push(info_event_queue, (mfEvent*) event);}
|
||||
);
|
||||
dispatch_resume(info_timer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOL mf_peer_post_connect(freerdp_peer* client)
|
||||
{
|
||||
mfPeerContext* context = (mfPeerContext*) client->context;
|
||||
rdpSettings* settings = client->settings;
|
||||
|
||||
rdpSettings* settings = client->settings;
|
||||
|
||||
printf("Client %s post connect\n", client->hostname);
|
||||
|
||||
|
||||
if (client->settings->AutoLogonEnabled)
|
||||
{
|
||||
printf(" and wants to login automatically as %s\\%s",
|
||||
client->settings->Domain ? client->settings->Domain : "",
|
||||
client->settings->Username);
|
||||
|
||||
client->settings->Domain ? client->settings->Domain : "",
|
||||
client->settings->Username);
|
||||
|
||||
/* A real server may perform OS login here if NLA is not executed previously. */
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
mfInfo* mfi = mf_info_get_instance();
|
||||
mfi->scale = 1;
|
||||
|
||||
//mfi->servscreen_width = 2880 / mfi->scale;
|
||||
//mfi->servscreen_height = 1800 / mfi->scale;
|
||||
UINT32 bitsPerPixel = 32;
|
||||
|
||||
if ((settings->DesktopWidth != mfi->servscreen_width) || (settings->DesktopHeight != mfi->servscreen_height))
|
||||
|
||||
mfInfo* mfi = mf_info_get_instance();
|
||||
mfi->scale = 1;
|
||||
|
||||
//mfi->servscreen_width = 2880 / mfi->scale;
|
||||
//mfi->servscreen_height = 1800 / mfi->scale;
|
||||
UINT32 bitsPerPixel = 32;
|
||||
|
||||
if ((settings->DesktopWidth != mfi->servscreen_width) || (settings->DesktopHeight != mfi->servscreen_height))
|
||||
{
|
||||
printf("Client requested resolution %dx%d, but will resize to %dx%d\n",
|
||||
settings->DesktopWidth, settings->DesktopHeight, mfi->servscreen_width, mfi->servscreen_height);
|
||||
}
|
||||
|
||||
settings->DesktopWidth = mfi->servscreen_width;
|
||||
settings->DesktopHeight = mfi->servscreen_height;
|
||||
settings->ColorDepth = bitsPerPixel;
|
||||
|
||||
client->update->DesktopResize(client->update->context);
|
||||
settings->DesktopWidth, settings->DesktopHeight, mfi->servscreen_width, mfi->servscreen_height);
|
||||
}
|
||||
|
||||
|
||||
//#ifdef WITH_SERVER_CHANNELS
|
||||
settings->DesktopWidth = mfi->servscreen_width;
|
||||
settings->DesktopHeight = mfi->servscreen_height;
|
||||
settings->ColorDepth = bitsPerPixel;
|
||||
|
||||
client->update->DesktopResize(client->update->context);
|
||||
|
||||
|
||||
//#ifdef WITH_SERVER_CHANNELS
|
||||
/* Iterate all channel names requested by the client and activate those supported by the server */
|
||||
int i;
|
||||
int i;
|
||||
for (i = 0; i < client->settings->ChannelCount; i++)
|
||||
{
|
||||
if (client->settings->ChannelDefArray[i].joined)
|
||||
{
|
||||
//#ifdef CHANNEL_RDPSND_SERVER
|
||||
//#ifdef CHANNEL_RDPSND_SERVER
|
||||
if (strncmp(client->settings->ChannelDefArray[i].Name, "rdpsnd", 6) == 0)
|
||||
{
|
||||
mf_peer_rdpsnd_init(context); /* Audio Output */
|
||||
}
|
||||
//#endif
|
||||
//#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Dynamic Virtual Channels */
|
||||
//#endif
|
||||
|
||||
//#endif
|
||||
|
||||
#ifdef CHANNEL_AUDIN_SERVER
|
||||
mf_peer_audin_init(context); /* Audio Input */
|
||||
#endif
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -334,27 +319,27 @@ BOOL mf_peer_post_connect(freerdp_peer* client)
|
||||
BOOL mf_peer_activate(freerdp_peer* client)
|
||||
{
|
||||
mfPeerContext* context = (mfPeerContext*) client->context;
|
||||
|
||||
|
||||
rfx_context_reset(context->rfx_context);
|
||||
context->activated = TRUE;
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*BOOL wf_peer_logon(freerdp_peer* client, SEC_WINNT_AUTH_IDENTITY* identity, BOOL automatic)
|
||||
{
|
||||
printf("PeerLogon\n");
|
||||
|
||||
if (automatic)
|
||||
{
|
||||
_tprintf(_T("Logon: User:%s Domain:%s Password:%s\n"),
|
||||
identity->User, identity->Domain, identity->Password);
|
||||
}
|
||||
|
||||
|
||||
wfreerdp_server_peer_callback_event(((rdpContext*) client->context)->peer->pId, WF_SRV_CALLBACK_EVENT_AUTH);
|
||||
return TRUE;
|
||||
}*/
|
||||
{
|
||||
printf("PeerLogon\n");
|
||||
|
||||
if (automatic)
|
||||
{
|
||||
_tprintf(_T("Logon: User:%s Domain:%s Password:%s\n"),
|
||||
identity->User, identity->Domain, identity->Password);
|
||||
}
|
||||
|
||||
|
||||
wfreerdp_server_peer_callback_event(((rdpContext*) client->context)->peer->pId, WF_SRV_CALLBACK_EVENT_AUTH);
|
||||
return TRUE;
|
||||
}*/
|
||||
|
||||
void mf_peer_synchronize_event(rdpInput* input, UINT32 flags)
|
||||
{
|
||||
@ -364,23 +349,23 @@ void mf_peer_synchronize_event(rdpInput* input, UINT32 flags)
|
||||
void mf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
|
||||
{
|
||||
printf("Client sent a keyboard event (flags:0x%04X code:0x%04X)\n", flags, code);
|
||||
|
||||
UINT16 down = 0x4000;
|
||||
//UINT16 up = 0x8000;
|
||||
|
||||
bool state_down = FALSE;
|
||||
|
||||
if (flags == down)
|
||||
{
|
||||
state_down = TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
CGEventRef event;
|
||||
event = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)code, state_down);
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
CFRelease(event);
|
||||
*/
|
||||
|
||||
UINT16 down = 0x4000;
|
||||
//UINT16 up = 0x8000;
|
||||
|
||||
bool state_down = FALSE;
|
||||
|
||||
if (flags == down)
|
||||
{
|
||||
state_down = TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
CGEventRef event;
|
||||
event = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)code, state_down);
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
CFRelease(event);
|
||||
*/
|
||||
}
|
||||
|
||||
void mf_peer_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
|
||||
@ -399,16 +384,16 @@ void mf_peer_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT1
|
||||
}
|
||||
|
||||
/*static void mf_peer_refresh_rect(rdpContext* context, BYTE count, RECTANGLE_16* areas)
|
||||
{
|
||||
BYTE i;
|
||||
|
||||
printf("Client requested to refresh:\n");
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
printf(" (%d, %d) (%d, %d)\n", areas[i].left, areas[i].top, areas[i].right, areas[i].bottom);
|
||||
}
|
||||
}*/
|
||||
{
|
||||
BYTE i;
|
||||
|
||||
printf("Client requested to refresh:\n");
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
printf(" (%d, %d) (%d, %d)\n", areas[i].left, areas[i].top, areas[i].right, areas[i].bottom);
|
||||
}
|
||||
}*/
|
||||
|
||||
static void mf_peer_suppress_output(rdpContext* context, BYTE allow, RECTANGLE_16* area)
|
||||
{
|
||||
@ -425,74 +410,74 @@ static void mf_peer_suppress_output(rdpContext* context, BYTE allow, RECTANGLE_1
|
||||
void mf_peer_accepted(freerdp_listener* instance, freerdp_peer* client)
|
||||
{
|
||||
pthread_t th;
|
||||
|
||||
|
||||
pthread_create(&th, 0, mf_peer_main_loop, client);
|
||||
pthread_detach(th);
|
||||
}
|
||||
|
||||
/*DWORD WINAPI wf_peer_socket_listener(LPVOID lpParam)
|
||||
{
|
||||
int i, fds;
|
||||
int rcount;
|
||||
int max_fds;
|
||||
void* rfds[32];
|
||||
fd_set rfds_set;
|
||||
wfPeerContext* context;
|
||||
freerdp_peer* client = (freerdp_peer*) lpParam;
|
||||
|
||||
ZeroMemory(rfds, sizeof(rfds));
|
||||
context = (wfPeerContext*) client->context;
|
||||
|
||||
printf("PeerSocketListener\n");
|
||||
|
||||
while (1)
|
||||
{
|
||||
rcount = 0;
|
||||
|
||||
if (client->GetFileDescriptor(client, rfds, &rcount) != TRUE)
|
||||
{
|
||||
printf("Failed to get peer file descriptor\n");
|
||||
break;
|
||||
}
|
||||
|
||||
max_fds = 0;
|
||||
FD_ZERO(&rfds_set);
|
||||
|
||||
for (i = 0; i < rcount; i++)
|
||||
{
|
||||
fds = (int)(long)(rfds[i]);
|
||||
|
||||
if (fds > max_fds)
|
||||
max_fds = fds;
|
||||
|
||||
FD_SET(fds, &rfds_set);
|
||||
}
|
||||
|
||||
if (max_fds == 0)
|
||||
break;
|
||||
|
||||
select(max_fds + 1, &rfds_set, NULL, NULL, NULL);
|
||||
|
||||
SetEvent(context->socketEvent);
|
||||
WaitForSingleObject(context->socketSemaphore, INFINITE);
|
||||
|
||||
if (context->socketClose)
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Exiting Peer Socket Listener Thread\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wf_peer_read_settings(freerdp_peer* client)
|
||||
{
|
||||
if (!wf_settings_read_string_ascii(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), _T("CertificateFile"), &(client->settings->CertificateFile)))
|
||||
client->settings->CertificateFile = _strdup("server.crt");
|
||||
|
||||
if (!wf_settings_read_string_ascii(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), _T("PrivateKeyFile"), &(client->settings->PrivateKeyFile)))
|
||||
client->settings->PrivateKeyFile = _strdup("server.key");
|
||||
}*/
|
||||
{
|
||||
int i, fds;
|
||||
int rcount;
|
||||
int max_fds;
|
||||
void* rfds[32];
|
||||
fd_set rfds_set;
|
||||
wfPeerContext* context;
|
||||
freerdp_peer* client = (freerdp_peer*) lpParam;
|
||||
|
||||
ZeroMemory(rfds, sizeof(rfds));
|
||||
context = (wfPeerContext*) client->context;
|
||||
|
||||
printf("PeerSocketListener\n");
|
||||
|
||||
while (1)
|
||||
{
|
||||
rcount = 0;
|
||||
|
||||
if (client->GetFileDescriptor(client, rfds, &rcount) != TRUE)
|
||||
{
|
||||
printf("Failed to get peer file descriptor\n");
|
||||
break;
|
||||
}
|
||||
|
||||
max_fds = 0;
|
||||
FD_ZERO(&rfds_set);
|
||||
|
||||
for (i = 0; i < rcount; i++)
|
||||
{
|
||||
fds = (int)(long)(rfds[i]);
|
||||
|
||||
if (fds > max_fds)
|
||||
max_fds = fds;
|
||||
|
||||
FD_SET(fds, &rfds_set);
|
||||
}
|
||||
|
||||
if (max_fds == 0)
|
||||
break;
|
||||
|
||||
select(max_fds + 1, &rfds_set, NULL, NULL, NULL);
|
||||
|
||||
SetEvent(context->socketEvent);
|
||||
WaitForSingleObject(context->socketSemaphore, INFINITE);
|
||||
|
||||
if (context->socketClose)
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Exiting Peer Socket Listener Thread\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wf_peer_read_settings(freerdp_peer* client)
|
||||
{
|
||||
if (!wf_settings_read_string_ascii(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), _T("CertificateFile"), &(client->settings->CertificateFile)))
|
||||
client->settings->CertificateFile = _strdup("server.crt");
|
||||
|
||||
if (!wf_settings_read_string_ascii(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), _T("PrivateKeyFile"), &(client->settings->PrivateKeyFile)))
|
||||
client->settings->PrivateKeyFile = _strdup("server.key");
|
||||
}*/
|
||||
|
||||
void* mf_peer_main_loop(void* arg)
|
||||
{
|
||||
@ -504,11 +489,11 @@ void* mf_peer_main_loop(void* arg)
|
||||
fd_set rfds_set;
|
||||
mfPeerContext* context;
|
||||
freerdp_peer* client = (freerdp_peer*) arg;
|
||||
|
||||
|
||||
memset(rfds, 0, sizeof(rfds));
|
||||
|
||||
|
||||
mf_peer_init(client);
|
||||
|
||||
|
||||
/* Initialize the real server settings here */
|
||||
client->settings->CertificateFile = _strdup("server.crt");
|
||||
client->settings->PrivateKeyFile = _strdup("server.key");
|
||||
@ -517,73 +502,73 @@ void* mf_peer_main_loop(void* arg)
|
||||
client->settings->ColorDepth = 32;
|
||||
client->settings->SuppressOutput = TRUE;
|
||||
client->settings->RefreshRect = FALSE;
|
||||
|
||||
|
||||
client->PostConnect = mf_peer_post_connect;
|
||||
client->Activate = mf_peer_activate;
|
||||
|
||||
|
||||
client->input->SynchronizeEvent = mf_peer_synchronize_event;
|
||||
client->input->KeyboardEvent = mf_peer_keyboard_event;
|
||||
client->input->UnicodeKeyboardEvent = mf_peer_unicode_keyboard_event;
|
||||
client->input->MouseEvent = mf_peer_mouse_event;
|
||||
client->input->ExtendedMouseEvent = mf_peer_extended_mouse_event;
|
||||
|
||||
|
||||
//client->update->RefreshRect = mf_peer_refresh_rect;
|
||||
client->update->SuppressOutput = mf_peer_suppress_output;
|
||||
|
||||
|
||||
client->Initialize(client);
|
||||
context = (mfPeerContext*) client->context;
|
||||
|
||||
|
||||
printf("We've got a client %s\n", client->local ? "(local)" : client->hostname);
|
||||
|
||||
|
||||
while (1)
|
||||
{
|
||||
rcount = 0;
|
||||
|
||||
|
||||
if (client->GetFileDescriptor(client, rfds, &rcount) != TRUE)
|
||||
{
|
||||
printf("Failed to get FreeRDP file descriptor\n");
|
||||
break;
|
||||
}
|
||||
if (mf_peer_get_fds(client, rfds, &rcount) != TRUE)
|
||||
if (mf_peer_get_fds(client, rfds, &rcount) != TRUE)
|
||||
{
|
||||
printf("Failed to get mfreerdp file descriptor\n");
|
||||
break;
|
||||
}
|
||||
|
||||
//#ifdef WITH_SERVER_CHANNELS
|
||||
|
||||
//#ifdef WITH_SERVER_CHANNELS
|
||||
WTSVirtualChannelManagerGetFileDescriptor(context->vcm, rfds, &rcount);
|
||||
//#endif
|
||||
|
||||
//#endif
|
||||
|
||||
max_fds = 0;
|
||||
FD_ZERO(&rfds_set);
|
||||
|
||||
|
||||
for (i = 0; i < rcount; i++)
|
||||
{
|
||||
fds = (int)(long)(rfds[i]);
|
||||
|
||||
|
||||
if (fds > max_fds)
|
||||
max_fds = fds;
|
||||
|
||||
|
||||
FD_SET(fds, &rfds_set);
|
||||
}
|
||||
|
||||
|
||||
if (max_fds == 0)
|
||||
break;
|
||||
|
||||
|
||||
if (select(max_fds + 1, &rfds_set, NULL, NULL, NULL) == -1)
|
||||
{
|
||||
/* these are not really errors */
|
||||
if (!((errno == EAGAIN) ||
|
||||
(errno == EWOULDBLOCK) ||
|
||||
(errno == EINPROGRESS) ||
|
||||
(errno == EINTR))) /* signal occurred */
|
||||
(errno == EWOULDBLOCK) ||
|
||||
(errno == EINPROGRESS) ||
|
||||
(errno == EINTR))) /* signal occurred */
|
||||
{
|
||||
printf("select failed\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (client->CheckFileDescriptor(client) != TRUE)
|
||||
|
||||
if (client->CheckFileDescriptor(client) != TRUE)
|
||||
{
|
||||
printf("Failed to check freerdp file descriptor\n");
|
||||
break;
|
||||
@ -593,20 +578,20 @@ void* mf_peer_main_loop(void* arg)
|
||||
printf("Failed to check mfreerdp file descriptor\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//#ifdef WITH_SERVER_CHANNELS
|
||||
|
||||
|
||||
//#ifdef WITH_SERVER_CHANNELS
|
||||
if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE)
|
||||
break;
|
||||
//#endif
|
||||
|
||||
//#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
printf("Client %s disconnected.\n", client->local ? "(local)" : client->hostname);
|
||||
|
||||
|
||||
client->Disconnect(client);
|
||||
freerdp_peer_context_free(client);
|
||||
freerdp_peer_free(client);
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -44,107 +44,94 @@ static const rdpsndFormat audio_formats[] =
|
||||
|
||||
static void mf_peer_rdpsnd_activated(rdpsnd_server_context* context)
|
||||
{
|
||||
printf("RDPSND Activated\n");
|
||||
|
||||
|
||||
|
||||
printf("Let's create an audio queue for input!\n");
|
||||
|
||||
OSStatus status;
|
||||
|
||||
recorderState.dataFormat.mSampleRate = 44100.0;
|
||||
recorderState.dataFormat.mFormatID = kAudioFormatLinearPCM;
|
||||
recorderState.dataFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
|
||||
recorderState.dataFormat.mBytesPerPacket = 4;
|
||||
recorderState.dataFormat.mFramesPerPacket = 1;
|
||||
recorderState.dataFormat.mBytesPerFrame = 4;
|
||||
recorderState.dataFormat.mChannelsPerFrame = 2;
|
||||
recorderState.dataFormat.mBitsPerChannel = 16;
|
||||
|
||||
recorderState.snd_context = context;
|
||||
|
||||
status = AudioQueueNewInput(&recorderState.dataFormat,
|
||||
mf_peer_rdpsnd_input_callback,
|
||||
&recorderState,
|
||||
NULL,
|
||||
kCFRunLoopCommonModes,
|
||||
0,
|
||||
&recorderState.queue);
|
||||
|
||||
if (status != noErr)
|
||||
{
|
||||
printf("Failed to create a new Audio Queue. Status code: %d\n", 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);
|
||||
|
||||
|
||||
printf("Preparing a set of buffers...");
|
||||
|
||||
for (int i = 0; i < snd_numBuffers; ++i)
|
||||
{
|
||||
AudioQueueAllocateBuffer(recorderState.queue,
|
||||
recorderState.bufferByteSize,
|
||||
&recorderState.buffers[i]);
|
||||
|
||||
AudioQueueEnqueueBuffer(recorderState.queue,
|
||||
recorderState.buffers[i],
|
||||
0,
|
||||
NULL);
|
||||
}
|
||||
|
||||
printf("done\n");
|
||||
|
||||
printf("recording...\n");
|
||||
|
||||
|
||||
|
||||
recorderState.currentPacket = 0;
|
||||
recorderState.isRunning = true;
|
||||
|
||||
context->SelectFormat(context, 4);
|
||||
context->SetVolume(context, 0x7FFF, 0x7FFF);
|
||||
|
||||
AudioQueueStart (recorderState.queue, NULL);
|
||||
|
||||
OSStatus status;
|
||||
|
||||
recorderState.dataFormat.mSampleRate = 44100.0;
|
||||
recorderState.dataFormat.mFormatID = kAudioFormatLinearPCM;
|
||||
recorderState.dataFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
|
||||
recorderState.dataFormat.mBytesPerPacket = 4;
|
||||
recorderState.dataFormat.mFramesPerPacket = 1;
|
||||
recorderState.dataFormat.mBytesPerFrame = 4;
|
||||
recorderState.dataFormat.mChannelsPerFrame = 2;
|
||||
recorderState.dataFormat.mBitsPerChannel = 16;
|
||||
|
||||
recorderState.snd_context = context;
|
||||
|
||||
status = AudioQueueNewInput(&recorderState.dataFormat,
|
||||
mf_peer_rdpsnd_input_callback,
|
||||
&recorderState,
|
||||
NULL,
|
||||
kCFRunLoopCommonModes,
|
||||
0,
|
||||
&recorderState.queue);
|
||||
|
||||
if (status != noErr)
|
||||
{
|
||||
printf("Failed to create a new Audio Queue. Status code: %d\n", 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 (int i = 0; i < snd_numBuffers; ++i)
|
||||
{
|
||||
AudioQueueAllocateBuffer(recorderState.queue,
|
||||
recorderState.bufferByteSize,
|
||||
&recorderState.buffers[i]);
|
||||
|
||||
AudioQueueEnqueueBuffer(recorderState.queue,
|
||||
recorderState.buffers[i],
|
||||
0,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
recorderState.currentPacket = 0;
|
||||
recorderState.isRunning = true;
|
||||
|
||||
context->SelectFormat(context, 4);
|
||||
context->SetVolume(context, 0x7FFF, 0x7FFF);
|
||||
|
||||
AudioQueueStart (recorderState.queue, NULL);
|
||||
|
||||
}
|
||||
|
||||
BOOL mf_peer_rdpsnd_init(mfPeerContext* context)
|
||||
{
|
||||
//printf("RDPSND INIT\n");
|
||||
context->rdpsnd = rdpsnd_server_context_new(context->vcm);
|
||||
context->rdpsnd->data = context;
|
||||
|
||||
|
||||
context->rdpsnd->server_formats = audio_formats;
|
||||
context->rdpsnd->num_server_formats = sizeof(audio_formats) / sizeof(audio_formats[0]);
|
||||
|
||||
|
||||
context->rdpsnd->src_format.wFormatTag = 1;
|
||||
context->rdpsnd->src_format.nChannels = 2;
|
||||
context->rdpsnd->src_format.nSamplesPerSec = 44100;
|
||||
context->rdpsnd->src_format.wBitsPerSample = 16;
|
||||
|
||||
|
||||
context->rdpsnd->Activated = mf_peer_rdpsnd_activated;
|
||||
|
||||
|
||||
context->rdpsnd->Initialize(context->rdpsnd);
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL mf_peer_rdpsnd_stop()
|
||||
{
|
||||
recorderState.isRunning = false;
|
||||
AudioQueueStop(recorderState.queue, true);
|
||||
|
||||
return TRUE;
|
||||
recorderState.isRunning = false;
|
||||
AudioQueueStop(recorderState.queue, true);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void mf_peer_rdpsnd_input_callback (void *inUserData,
|
||||
@ -154,35 +141,35 @@ void mf_peer_rdpsnd_input_callback (void *inUserD
|
||||
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);
|
||||
|
||||
status = AudioQueueEnqueueBuffer(
|
||||
rState->queue,
|
||||
inBuffer,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
if (status != noErr)
|
||||
{
|
||||
printf("AudioQueueEnqueueBuffer() returned status = %d\n", status);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
status = AudioQueueEnqueueBuffer(
|
||||
rState->queue,
|
||||
inBuffer,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
if (status != noErr)
|
||||
{
|
||||
printf("AudioQueueEnqueueBuffer() returned status = %d\n", status);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void mf_rdpsnd_derive_buffer_size (AudioQueueRef audioQueue,
|
||||
@ -190,23 +177,23 @@ void mf_rdpsnd_derive_buffer_size (AudioQueueRef audioQueue,
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -36,25 +36,25 @@ void mf_rdpsnd_derive_buffer_size (AudioQueueRef audioQueue,
|
||||
UInt32 *outBufferSize);
|
||||
|
||||
void mf_peer_rdpsnd_input_callback (void *inUserData,
|
||||
AudioQueueRef inAQ,
|
||||
AudioQueueBufferRef inBuffer,
|
||||
const AudioTimeStamp *inStartTime,
|
||||
UInt32 inNumberPacketDescriptions,
|
||||
const AudioStreamPacketDescription *inPacketDescs);
|
||||
AudioQueueRef inAQ,
|
||||
AudioQueueBufferRef inBuffer,
|
||||
const AudioTimeStamp *inStartTime,
|
||||
UInt32 inNumberPacketDescriptions,
|
||||
const AudioStreamPacketDescription *inPacketDescs);
|
||||
|
||||
|
||||
static const int snd_numBuffers = 3;
|
||||
struct _AQRecorderState
|
||||
{
|
||||
AudioStreamBasicDescription dataFormat;
|
||||
AudioQueueRef queue;
|
||||
AudioQueueBufferRef buffers[snd_numBuffers];
|
||||
AudioFileID audioFile;
|
||||
UInt32 bufferByteSize;
|
||||
SInt64 currentPacket;
|
||||
bool isRunning;
|
||||
rdpsnd_server_context* snd_context;
|
||||
|
||||
AudioStreamBasicDescription dataFormat;
|
||||
AudioQueueRef queue;
|
||||
AudioQueueBufferRef buffers[snd_numBuffers];
|
||||
AudioFileID audioFile;
|
||||
UInt32 bufferByteSize;
|
||||
SInt64 currentPacket;
|
||||
bool isRunning;
|
||||
rdpsnd_server_context* snd_context;
|
||||
|
||||
};
|
||||
|
||||
typedef struct _AQRecorderState AQRecorderState;
|
||||
|
@ -33,12 +33,30 @@ set(${MODULE_PREFIX}_SRCS
|
||||
wf_mirage.h
|
||||
wf_peer.c
|
||||
wf_peer.h
|
||||
wf_rdpsnd.c
|
||||
wf_rdpsnd.h
|
||||
wf_settings.c
|
||||
wf_settings.h
|
||||
wf_info.c
|
||||
wf_info.h)
|
||||
|
||||
if(CHANNEL_RDPSND AND NOT WITH_RDPSND_DSOUND)
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
${${MODULE_PREFIX}_SRCS}
|
||||
wf_rdpsnd.c
|
||||
wf_rdpsnd.h
|
||||
wf_wasapi.c
|
||||
wf_wasapi.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CHANNEL_RDPSND AND WITH_RDPSND_DSOUND)
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
${${MODULE_PREFIX}_SRCS}
|
||||
wf_rdpsnd.c
|
||||
wf_rdpsnd.h
|
||||
wf_directsound.c
|
||||
wf_directsound.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_SERVER_INTERFACE)
|
||||
add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
||||
|
203
server/Windows/wf_directsound.c
Normal file
203
server/Windows/wf_directsound.c
Normal file
@ -0,0 +1,203 @@
|
||||
#include "wf_directsound.h"
|
||||
#include "wf_interface.h"
|
||||
#include "wf_info.h"
|
||||
#include "wf_rdpsnd.h"
|
||||
|
||||
|
||||
#include <winpr/windows.h>
|
||||
|
||||
#define INITGUID
|
||||
#include <initguid.h>
|
||||
#include <objbase.h>
|
||||
|
||||
#define CINTERFACE 1
|
||||
#include <mmsystem.h>
|
||||
#include <dsound.h>
|
||||
|
||||
IDirectSoundCapture8* cap;
|
||||
IDirectSoundCaptureBuffer8* capBuf;
|
||||
DSCBUFFERDESC dscbd;
|
||||
DWORD lastPos;
|
||||
wfPeerContext* latestPeer;
|
||||
|
||||
int wf_rdpsnd_set_latest_peer(wfPeerContext* peer)
|
||||
{
|
||||
latestPeer = peer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wf_directsound_activate(rdpsnd_server_context* context)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
LPDIRECTSOUNDCAPTUREBUFFER pDSCB;
|
||||
WAVEFORMATEX wfx = {WAVE_FORMAT_PCM, 2, 44100, 176400, 4, 16, 0};
|
||||
|
||||
|
||||
printf("RDPSND (direct sound) Activated\n");
|
||||
|
||||
hr = DirectSoundCaptureCreate8(NULL, &cap, NULL);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to create sound capture device\n"));
|
||||
return 1;
|
||||
}
|
||||
_tprintf(_T("Created sound capture device\n"));
|
||||
|
||||
dscbd.dwSize = sizeof(DSCBUFFERDESC);
|
||||
dscbd.dwFlags = 0;
|
||||
dscbd.dwBufferBytes = 176400;
|
||||
dscbd.dwReserved = 0;
|
||||
dscbd.lpwfxFormat = &wfx;
|
||||
dscbd.dwFXCount = 0;
|
||||
dscbd.lpDSCFXDesc = NULL;
|
||||
|
||||
hr = cap->lpVtbl->CreateCaptureBuffer(cap, &dscbd, &pDSCB, NULL);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to create capture buffer\n"));
|
||||
}
|
||||
_tprintf(_T("Created capture buffer"));
|
||||
|
||||
hr = pDSCB->lpVtbl->QueryInterface(pDSCB, &IID_IDirectSoundCaptureBuffer8, (LPVOID*)&capBuf);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to QI capture buffer\n"));
|
||||
}
|
||||
_tprintf(_T("Created IDirectSoundCaptureBuffer8\n"));
|
||||
pDSCB->lpVtbl->Release(pDSCB);
|
||||
|
||||
context->SelectFormat(context, 4);
|
||||
context->SetVolume(context, 0x7FFF, 0x7FFF);
|
||||
lastPos = 0;
|
||||
|
||||
CreateThread(NULL, 0, wf_rdpsnd_directsound_thread, latestPeer, 0, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD WINAPI wf_rdpsnd_directsound_thread(LPVOID lpParam)
|
||||
{
|
||||
HRESULT hr;
|
||||
DWORD beg = 0;
|
||||
DWORD end = 0;
|
||||
DWORD diff, rate;
|
||||
wfPeerContext* context;
|
||||
wfInfo* wfi;
|
||||
|
||||
VOID* pbCaptureData = NULL;
|
||||
DWORD dwCaptureLength = 0;
|
||||
VOID* pbCaptureData2 = NULL;
|
||||
DWORD dwCaptureLength2 = 0;
|
||||
VOID* pbPlayData = NULL;
|
||||
DWORD dwReadPos = 0;
|
||||
LONG lLockSize = 0;
|
||||
|
||||
wfi = wf_info_get_instance();
|
||||
|
||||
context = (wfPeerContext*)lpParam;
|
||||
rate = 1000 / 24;
|
||||
|
||||
_tprintf(_T("Trying to start capture\n"));
|
||||
hr = capBuf->lpVtbl->Start(capBuf, DSCBSTART_LOOPING);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to start capture\n"));
|
||||
}
|
||||
_tprintf(_T("Capture started\n"));
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
||||
end = GetTickCount();
|
||||
diff = end - beg;
|
||||
|
||||
if (diff < rate)
|
||||
{
|
||||
Sleep(rate - diff);
|
||||
}
|
||||
|
||||
beg = GetTickCount();
|
||||
|
||||
if (wf_rdpsnd_lock() > 0)
|
||||
{
|
||||
//check for main exit condition
|
||||
if (wfi->snd_stop == TRUE)
|
||||
{
|
||||
wf_rdpsnd_unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
hr = capBuf->lpVtbl->GetCurrentPosition(capBuf, NULL, &dwReadPos);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to get read pos\n"));
|
||||
wf_rdpsnd_unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
lLockSize = dwReadPos - lastPos;//dscbd.dwBufferBytes;
|
||||
if (lLockSize < 0) lLockSize += dscbd.dwBufferBytes;
|
||||
|
||||
//printf("Last, read, lock = [%d, %d, %d]\n", lastPos, dwReadPos, lLockSize);
|
||||
|
||||
if (lLockSize == 0)
|
||||
{
|
||||
wf_rdpsnd_unlock();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
hr = capBuf->lpVtbl->Lock(capBuf, lastPos, lLockSize, &pbCaptureData, &dwCaptureLength, &pbCaptureData2, &dwCaptureLength2, 0L);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to lock sound capture buffer\n"));
|
||||
wf_rdpsnd_unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
//fwrite(pbCaptureData, 1, dwCaptureLength, pFile);
|
||||
//fwrite(pbCaptureData2, 1, dwCaptureLength2, pFile);
|
||||
|
||||
//FIXME: frames = bytes/(bytespersample * channels)
|
||||
|
||||
context->rdpsnd->SendSamples(context->rdpsnd, pbCaptureData, dwCaptureLength/4);
|
||||
context->rdpsnd->SendSamples(context->rdpsnd, pbCaptureData2, dwCaptureLength2/4);
|
||||
|
||||
|
||||
hr = capBuf->lpVtbl->Unlock(capBuf, pbCaptureData, dwCaptureLength, pbCaptureData2, dwCaptureLength2);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to unlock sound capture buffer\n"));
|
||||
wf_rdpsnd_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//TODO keep track of location in buffer
|
||||
lastPos += dwCaptureLength;
|
||||
lastPos %= dscbd.dwBufferBytes;
|
||||
lastPos += dwCaptureLength2;
|
||||
lastPos %= dscbd.dwBufferBytes;
|
||||
|
||||
wf_rdpsnd_unlock();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
_tprintf(_T("Trying to stop sound capture\n"));
|
||||
hr = capBuf->lpVtbl->Stop(capBuf);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to stop capture\n"));
|
||||
}
|
||||
_tprintf(_T("Capture stopped\n"));
|
||||
capBuf->lpVtbl->Release(capBuf);
|
||||
cap->lpVtbl->Release(cap);
|
||||
|
||||
lastPos = 0;
|
||||
|
||||
return 0;
|
||||
}
|
13
server/Windows/wf_directsound.h
Normal file
13
server/Windows/wf_directsound.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef WF_DSOUND_H
|
||||
#define WF_DSOUND_H
|
||||
|
||||
#include <freerdp/server/rdpsnd.h>
|
||||
#include "wf_interface.h"
|
||||
|
||||
int wf_rdpsnd_set_latest_peer(wfPeerContext* peer);
|
||||
|
||||
int wf_directsound_activate(rdpsnd_server_context* context);
|
||||
|
||||
DWORD WINAPI wf_rdpsnd_directsound_thread(LPVOID lpParam);
|
||||
|
||||
#endif
|
@ -54,7 +54,8 @@ int get_screen_info(int id, _TCHAR* name, int* width, int* height, int* bpp)
|
||||
*width = GetDeviceCaps(dc, HORZRES);
|
||||
*height = GetDeviceCaps(dc, VERTRES);
|
||||
*bpp = GetDeviceCaps(dc, BITSPIXEL);
|
||||
ReleaseDC(NULL, dc);
|
||||
//ReleaseDC(NULL, dc);
|
||||
DeleteDC(dc);
|
||||
|
||||
}
|
||||
else
|
||||
|
@ -3,6 +3,7 @@
|
||||
* FreeRDP Windows Server (Audio Output)
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2013 Corey Clayton <can.of.tuna@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -26,32 +27,19 @@
|
||||
|
||||
#include <winpr/windows.h>
|
||||
|
||||
#define INITGUID
|
||||
#include <initguid.h>
|
||||
#include <objbase.h>
|
||||
|
||||
#define CINTERFACE
|
||||
#include <mmsystem.h>
|
||||
#include <dsound.h>
|
||||
|
||||
#include <freerdp/server/rdpsnd.h>
|
||||
|
||||
#include "wf_rdpsnd.h"
|
||||
#include "wf_info.h"
|
||||
|
||||
/*
|
||||
* Here are some temp things that shall be moved
|
||||
*
|
||||
*/
|
||||
IDirectSoundCapture8* cap;
|
||||
IDirectSoundCaptureBuffer8* capBuf;
|
||||
DSCBUFFERDESC dscbd;
|
||||
DWORD lastPos;
|
||||
#ifdef WITH_RDPSND_DSOUND
|
||||
|
||||
#define BYTESPERSEC 176400
|
||||
#include "wf_directsound.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "wf_wasapi.h"
|
||||
|
||||
#endif
|
||||
|
||||
//FIXME support multiple clients
|
||||
wfPeerContext* latestPeer;
|
||||
|
||||
static const rdpsndFormat test_audio_formats[] =
|
||||
{
|
||||
@ -69,54 +57,16 @@ static const rdpsndFormat test_audio_formats[] =
|
||||
|
||||
static void wf_peer_rdpsnd_activated(rdpsnd_server_context* context)
|
||||
{
|
||||
HRESULT hr;
|
||||
#ifdef WITH_RDPSND_DSOUND
|
||||
|
||||
wf_directsound_activate(context);
|
||||
|
||||
#else
|
||||
|
||||
wf_wasapi_activate(context);
|
||||
|
||||
#endif
|
||||
|
||||
LPDIRECTSOUNDCAPTUREBUFFER pDSCB;
|
||||
WAVEFORMATEX wfx = {WAVE_FORMAT_PCM, 2, 44100, BYTESPERSEC, 4, 16, 0};
|
||||
|
||||
|
||||
printf("RDPSND Activated\n");
|
||||
|
||||
hr = DirectSoundCaptureCreate8(NULL, &cap, NULL);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to create sound capture device\n"));
|
||||
return;
|
||||
}
|
||||
_tprintf(_T("Created sound capture device\n"));
|
||||
|
||||
dscbd.dwSize = sizeof(DSCBUFFERDESC);
|
||||
dscbd.dwFlags = 0;
|
||||
dscbd.dwBufferBytes = BYTESPERSEC;
|
||||
dscbd.dwReserved = 0;
|
||||
dscbd.lpwfxFormat = &wfx;
|
||||
dscbd.dwFXCount = 0;
|
||||
dscbd.lpDSCFXDesc = NULL;
|
||||
|
||||
hr = cap->lpVtbl->CreateCaptureBuffer(cap, &dscbd, &pDSCB, NULL);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to create capture buffer\n"));
|
||||
}
|
||||
_tprintf(_T("Created capture buffer"));
|
||||
|
||||
hr = pDSCB->lpVtbl->QueryInterface(pDSCB, &IID_IDirectSoundCaptureBuffer8, (LPVOID*)&capBuf);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to QI capture buffer\n"));
|
||||
}
|
||||
_tprintf(_T("Created IDirectSoundCaptureBuffer8\n"));
|
||||
pDSCB->lpVtbl->Release(pDSCB);
|
||||
|
||||
context->SelectFormat(context, 4);
|
||||
context->SetVolume(context, 0x7FFF, 0x7FFF);
|
||||
lastPos = 0;
|
||||
|
||||
CreateThread(NULL, 0, wf_rdpsnd_thread, latestPeer, 0, NULL);
|
||||
|
||||
|
||||
}
|
||||
|
||||
int wf_rdpsnd_lock()
|
||||
@ -186,131 +136,9 @@ BOOL wf_peer_rdpsnd_init(wfPeerContext* context)
|
||||
|
||||
context->rdpsnd->Initialize(context->rdpsnd);
|
||||
|
||||
latestPeer = context;
|
||||
wf_rdpsnd_set_latest_peer(context);
|
||||
|
||||
wfi->snd_stop = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DWORD WINAPI wf_rdpsnd_thread(LPVOID lpParam)
|
||||
{
|
||||
HRESULT hr;
|
||||
DWORD beg = 0;
|
||||
DWORD end = 0;
|
||||
DWORD diff, rate;
|
||||
wfPeerContext* context;
|
||||
wfInfo* wfi;
|
||||
|
||||
VOID* pbCaptureData = NULL;
|
||||
DWORD dwCaptureLength = 0;
|
||||
VOID* pbCaptureData2 = NULL;
|
||||
DWORD dwCaptureLength2 = 0;
|
||||
VOID* pbPlayData = NULL;
|
||||
DWORD dwReadPos = 0;
|
||||
LONG lLockSize = 0;
|
||||
|
||||
wfi = wf_info_get_instance();
|
||||
|
||||
context = (wfPeerContext*)lpParam;
|
||||
rate = 1000 / 24;
|
||||
|
||||
_tprintf(_T("Trying to start capture\n"));
|
||||
hr = capBuf->lpVtbl->Start(capBuf, DSCBSTART_LOOPING);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to start capture\n"));
|
||||
}
|
||||
_tprintf(_T("Capture started\n"));
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
||||
end = GetTickCount();
|
||||
diff = end - beg;
|
||||
|
||||
if (diff < rate)
|
||||
{
|
||||
Sleep(rate - diff);
|
||||
}
|
||||
|
||||
beg = GetTickCount();
|
||||
|
||||
if (wf_rdpsnd_lock() > 0)
|
||||
{
|
||||
//check for main exit condition
|
||||
if (wfi->snd_stop == TRUE)
|
||||
{
|
||||
wf_rdpsnd_unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
hr = capBuf->lpVtbl->GetCurrentPosition(capBuf, NULL, &dwReadPos);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to get read pos\n"));
|
||||
wf_rdpsnd_unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
lLockSize = dwReadPos - lastPos;//dscbd.dwBufferBytes;
|
||||
if (lLockSize < 0) lLockSize += dscbd.dwBufferBytes;
|
||||
|
||||
//printf("Last, read, lock = [%d, %d, %d]\n", lastPos, dwReadPos, lLockSize);
|
||||
|
||||
if (lLockSize == 0)
|
||||
{
|
||||
wf_rdpsnd_unlock();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
hr = capBuf->lpVtbl->Lock(capBuf, lastPos, lLockSize, &pbCaptureData, &dwCaptureLength, &pbCaptureData2, &dwCaptureLength2, 0L);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to lock sound capture buffer\n"));
|
||||
wf_rdpsnd_unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
//fwrite(pbCaptureData, 1, dwCaptureLength, pFile);
|
||||
//fwrite(pbCaptureData2, 1, dwCaptureLength2, pFile);
|
||||
|
||||
//FIXME: frames = bytes/(bytespersample * channels)
|
||||
|
||||
context->rdpsnd->SendSamples(context->rdpsnd, pbCaptureData, dwCaptureLength/4);
|
||||
context->rdpsnd->SendSamples(context->rdpsnd, pbCaptureData2, dwCaptureLength2/4);
|
||||
|
||||
|
||||
hr = capBuf->lpVtbl->Unlock(capBuf, pbCaptureData, dwCaptureLength, pbCaptureData2, dwCaptureLength2);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to unlock sound capture buffer\n"));
|
||||
wf_rdpsnd_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//TODO keep track of location in buffer
|
||||
lastPos += dwCaptureLength;
|
||||
lastPos %= dscbd.dwBufferBytes;
|
||||
lastPos += dwCaptureLength2;
|
||||
lastPos %= dscbd.dwBufferBytes;
|
||||
|
||||
wf_rdpsnd_unlock();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
_tprintf(_T("Trying to stop sound capture\n"));
|
||||
hr = capBuf->lpVtbl->Stop(capBuf);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to stop capture\n"));
|
||||
}
|
||||
_tprintf(_T("Capture stopped\n"));
|
||||
capBuf->lpVtbl->Release(capBuf);
|
||||
cap->lpVtbl->Release(cap);
|
||||
|
||||
lastPos = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -30,7 +30,6 @@ int wf_rdpsnd_lock(void);
|
||||
int wf_rdpsnd_unlock(void);
|
||||
BOOL wf_peer_rdpsnd_init(wfPeerContext* context);
|
||||
|
||||
DWORD WINAPI wf_rdpsnd_thread(LPVOID lpParam);
|
||||
|
||||
#endif /* WF_RDPSND_H */
|
||||
|
||||
|
333
server/Windows/wf_wasapi.c
Normal file
333
server/Windows/wf_wasapi.c
Normal file
@ -0,0 +1,333 @@
|
||||
|
||||
#include "wf_wasapi.h"
|
||||
#include "wf_info.h"
|
||||
|
||||
#include <initguid.h>
|
||||
#include <mmdeviceapi.h>
|
||||
#include <Functiondiscoverykeys_devpkey.h>
|
||||
#include <Audioclient.h>
|
||||
|
||||
//#define REFTIMES_PER_SEC 10000000
|
||||
//#define REFTIMES_PER_MILLISEC 10000
|
||||
|
||||
#define REFTIMES_PER_SEC 100000
|
||||
#define REFTIMES_PER_MILLISEC 100
|
||||
|
||||
//#define REFTIMES_PER_SEC 50000
|
||||
//#define REFTIMES_PER_MILLISEC 50
|
||||
|
||||
|
||||
DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xBCDE0395, 0xE52F, 0x467C,
|
||||
0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E);
|
||||
DEFINE_GUID(IID_IMMDeviceEnumerator, 0xA95664D2, 0x9614, 0x4F35,
|
||||
0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6);
|
||||
DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2);
|
||||
DEFINE_GUID(IID_IAudioCaptureClient, 0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x18,0x5c,0x39,0x5c,0xd3,0x17);
|
||||
|
||||
LPWSTR devStr = NULL;
|
||||
wfPeerContext* latestPeer = NULL;
|
||||
|
||||
int wf_rdpsnd_set_latest_peer(wfPeerContext* peer)
|
||||
{
|
||||
latestPeer = peer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wf_wasapi_activate(rdpsnd_server_context* context)
|
||||
{
|
||||
wchar_t * pattern = L"Stereo Mix";
|
||||
|
||||
wf_wasapi_get_device_string(pattern, &devStr);
|
||||
|
||||
if(devStr == NULL)
|
||||
{
|
||||
_tprintf(_T("Failed to match for output device! Disabling rdpsnd.\n"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("RDPSND (WASAPI) Activated\n");
|
||||
|
||||
context->SelectFormat(context, 4);
|
||||
context->SetVolume(context, 0x7FFF, 0x7FFF);
|
||||
|
||||
CreateThread(NULL, 0, wf_rdpsnd_wasapi_thread, latestPeer, 0, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wf_wasapi_get_device_string(LPWSTR pattern, LPWSTR * deviceStr)
|
||||
{
|
||||
HRESULT hr;
|
||||
IMMDeviceEnumerator *pEnumerator = NULL;
|
||||
IMMDeviceCollection *pCollection = NULL;
|
||||
IMMDevice *pEndpoint = NULL;
|
||||
IPropertyStore *pProps = NULL;
|
||||
LPWSTR pwszID = NULL;
|
||||
unsigned int count, i;
|
||||
|
||||
CoInitialize(NULL);
|
||||
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (void **) &pEnumerator);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to cocreate device enumerator\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hr = pEnumerator->lpVtbl->EnumAudioEndpoints(pEnumerator, eCapture, DEVICE_STATE_ACTIVE, &pCollection);
|
||||
if ( FAILED(hr) )
|
||||
{
|
||||
_tprintf(_T("Failed to create endpoint collection\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pCollection->lpVtbl->GetCount(pCollection, &count);
|
||||
_tprintf(_T("Num endpoints: %d\n"), count);
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
_tprintf(_T("No endpoints!\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
PROPVARIANT nameVar;
|
||||
PropVariantInit(&nameVar);
|
||||
|
||||
hr = pCollection->lpVtbl->Item(pCollection, i, &pEndpoint);
|
||||
if ( FAILED(hr) )
|
||||
{
|
||||
_tprintf(_T("Failed to get endpoint %d\n"), i);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
hr = pEndpoint->lpVtbl->GetId(pEndpoint, &pwszID);
|
||||
if ( FAILED(hr) )
|
||||
{
|
||||
_tprintf(_T("Failed to get endpoint ID\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
hr = pEndpoint->lpVtbl->OpenPropertyStore(pEndpoint, STGM_READ, &pProps);
|
||||
if ( FAILED(hr) )
|
||||
{
|
||||
_tprintf(_T("Failed to open property store\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
hr = pProps->lpVtbl->GetValue(pProps, &PKEY_Device_FriendlyName, &nameVar);
|
||||
if ( FAILED(hr) )
|
||||
{
|
||||
_tprintf(_T("Failed to get device friendly name\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//do this a more reliable way
|
||||
if (wcscmp(pattern, nameVar.pwszVal) < 0)
|
||||
{
|
||||
unsigned int devStrLen;
|
||||
_tprintf(_T("Using sound ouput endpoint: [%s] (%s)\n"), nameVar.pwszVal, pwszID);
|
||||
//_tprintf(_T("matched %d characters\n"), wcscmp(pattern, nameVar.pwszVal));
|
||||
|
||||
devStrLen = wcslen(pwszID);
|
||||
*deviceStr = (LPWSTR) malloc((devStrLen * 2) + 2);
|
||||
ZeroMemory(*deviceStr, (devStrLen * 2) + 2);
|
||||
wcscpy_s(*deviceStr, devStrLen+1, pwszID);
|
||||
}
|
||||
CoTaskMemFree(pwszID);
|
||||
pwszID = NULL;
|
||||
PropVariantClear(&nameVar);
|
||||
|
||||
pProps->lpVtbl->Release(pProps);
|
||||
pProps = NULL;
|
||||
|
||||
pEndpoint->lpVtbl->Release(pEndpoint);
|
||||
pEndpoint = NULL;
|
||||
|
||||
}
|
||||
|
||||
pCollection->lpVtbl->Release(pCollection);
|
||||
pCollection = NULL;
|
||||
|
||||
pEnumerator->lpVtbl->Release(pEnumerator);
|
||||
pEnumerator = NULL;
|
||||
CoUninitialize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
DWORD WINAPI wf_rdpsnd_wasapi_thread(LPVOID lpParam)
|
||||
{
|
||||
IMMDeviceEnumerator *pEnumerator = NULL;
|
||||
IMMDevice *pDevice = NULL;
|
||||
IAudioClient *pAudioClient = NULL;
|
||||
IAudioCaptureClient *pCaptureClient = NULL;
|
||||
WAVEFORMATEX *pwfx = NULL;
|
||||
HRESULT hr;
|
||||
REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;
|
||||
REFERENCE_TIME hnsActualDuration;
|
||||
UINT32 bufferFrameCount;
|
||||
UINT32 numFramesAvailable;
|
||||
UINT32 packetLength = 0;
|
||||
UINT32 dCount = 0;
|
||||
BYTE *pData;
|
||||
|
||||
wfPeerContext* context;
|
||||
wfInfo* wfi;
|
||||
|
||||
wfi = wf_info_get_instance();
|
||||
context = (wfPeerContext*)lpParam;
|
||||
|
||||
CoInitialize(NULL);
|
||||
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (void **) &pEnumerator);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to cocreate device enumerator\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hr = pEnumerator->lpVtbl->GetDevice(pEnumerator, devStr, &pDevice);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to cocreate get device\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hr = pDevice->lpVtbl->Activate(pDevice, &IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&pAudioClient);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to activate audio client\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hr = pAudioClient->lpVtbl->GetMixFormat(pAudioClient, &pwfx);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to get mix format\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//screw it, use our own format
|
||||
//WAVEFORMATEX wfx = {WAVE_FORMAT_PCM, 2, 44100, 176400, 4, 16, 0};
|
||||
pwfx->wFormatTag = WAVE_FORMAT_PCM;
|
||||
pwfx->nChannels = 2;
|
||||
pwfx->nSamplesPerSec = 44100;
|
||||
pwfx->nAvgBytesPerSec = 176400;
|
||||
pwfx->nBlockAlign = 4;
|
||||
pwfx->wBitsPerSample = 16;
|
||||
pwfx->cbSize = 0;
|
||||
|
||||
hr = pAudioClient->lpVtbl->Initialize(
|
||||
pAudioClient,
|
||||
AUDCLNT_SHAREMODE_SHARED,
|
||||
0,
|
||||
hnsRequestedDuration,
|
||||
0,
|
||||
pwfx,
|
||||
NULL);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to initialize the audio client\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hr = pAudioClient->lpVtbl->GetBufferSize(pAudioClient, &bufferFrameCount);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to get buffer size\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hr = pAudioClient->lpVtbl->GetService(pAudioClient, &IID_IAudioCaptureClient, (void **) &pCaptureClient);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to get the capture client\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
hnsActualDuration = (UINT32)REFTIMES_PER_SEC * bufferFrameCount / pwfx->nSamplesPerSec;
|
||||
|
||||
hr = pAudioClient->lpVtbl->Start(pAudioClient);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to start capture\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
dCount = 0;
|
||||
while(wfi->snd_stop == FALSE)
|
||||
{
|
||||
DWORD flags;
|
||||
|
||||
|
||||
Sleep(hnsActualDuration/REFTIMES_PER_MILLISEC/2);
|
||||
|
||||
hr = pCaptureClient->lpVtbl->GetNextPacketSize(pCaptureClient, &packetLength);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to get packet length\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while(packetLength != 0)
|
||||
{
|
||||
hr = pCaptureClient->lpVtbl->GetBuffer(pCaptureClient, &pData, &numFramesAvailable, &flags, NULL, NULL);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to get buffer\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//Here we are writing the audio data
|
||||
//not sure if this flag is ever set by the system; msdn is not clear about it
|
||||
if (!(flags & AUDCLNT_BUFFERFLAGS_SILENT))
|
||||
context->rdpsnd->SendSamples(context->rdpsnd, pData, packetLength);
|
||||
|
||||
hr = pCaptureClient->lpVtbl->ReleaseBuffer(pCaptureClient, numFramesAvailable);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to release buffer\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hr = pCaptureClient->lpVtbl->GetNextPacketSize(pCaptureClient, &packetLength);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to get packet length\n"));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pAudioClient->lpVtbl->Stop(pAudioClient);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
_tprintf(_T("Failed to stop audio client\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
CoTaskMemFree(pwfx);
|
||||
|
||||
if (pEnumerator != NULL)
|
||||
pEnumerator->lpVtbl->Release(pEnumerator);
|
||||
|
||||
if (pDevice != NULL)
|
||||
pDevice->lpVtbl->Release(pDevice);
|
||||
|
||||
if (pAudioClient != NULL)
|
||||
pAudioClient->lpVtbl->Release(pAudioClient);
|
||||
|
||||
if (pCaptureClient != NULL)
|
||||
pCaptureClient->lpVtbl->Release(pCaptureClient);
|
||||
|
||||
CoUninitialize();
|
||||
|
||||
return 0;
|
||||
}
|
15
server/Windows/wf_wasapi.h
Normal file
15
server/Windows/wf_wasapi.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef WF_WASAPI_H
|
||||
#define WF_WASAPI_H
|
||||
|
||||
#include <freerdp/server/rdpsnd.h>
|
||||
#include "wf_interface.h"
|
||||
|
||||
int wf_rdpsnd_set_latest_peer(wfPeerContext* peer);
|
||||
|
||||
int wf_wasapi_activate(rdpsnd_server_context* context);
|
||||
|
||||
int wf_wasapi_get_device_string(LPWSTR pattern, LPWSTR * deviceStr);
|
||||
|
||||
DWORD WINAPI wf_rdpsnd_wasapi_thread(LPVOID lpParam);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user