wfreerdp-server: merging Corey's sound support with C# binding improvements
This commit is contained in:
commit
e87df0b7cc
@ -72,6 +72,7 @@ struct rdp_freerdp_peer
|
|||||||
psPeerSendChannelData SendChannelData;
|
psPeerSendChannelData SendChannelData;
|
||||||
psPeerReceiveChannelData ReceiveChannelData;
|
psPeerReceiveChannelData ReceiveChannelData;
|
||||||
|
|
||||||
|
int pId;
|
||||||
UINT32 ack_frame_id;
|
UINT32 ack_frame_id;
|
||||||
BOOL local;
|
BOOL local;
|
||||||
BOOL connected;
|
BOOL connected;
|
||||||
|
@ -48,10 +48,13 @@ else()
|
|||||||
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
if(WITH_WIN8)
|
if(WITH_WIN8)
|
||||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} d3d11 dxgi dxguid)
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} d3d11 dxgi dxguid)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} dsound)
|
||||||
|
|
||||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-server)
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-server)
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
* FreeRDP: A Remote Desktop Protocol Client
|
||||||
* FreeRDP Windows Server
|
* FreeRDP Windows Server
|
||||||
*
|
*
|
||||||
* Copyright 2012 Corey Clayton <can.of.tuna@gmail.com>
|
* Copyright 2012 Corey Clayton <can.of.tuna@gmail.com>
|
||||||
@ -136,19 +136,32 @@ wfInfo* wf_info_init()
|
|||||||
_tprintf(_T("Failed to create update thread\n"));
|
_tprintf(_T("Failed to create update thread\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
wfi->peers = (freerdp_peer**) malloc(sizeof(freerdp_peer*) * 32);
|
wfi->peers = (freerdp_peer**) malloc(sizeof(freerdp_peer*) * WF_INFO_MAXPEERS);
|
||||||
|
memset(wfi->peers, 0, sizeof(freerdp_peer*) * WF_INFO_MAXPEERS);
|
||||||
|
|
||||||
wfi->framesPerSecond = 24;
|
//Set FPS
|
||||||
|
wfi->framesPerSecond = WF_INFO_DEFAULT_FPS;
|
||||||
|
|
||||||
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
|
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
|
||||||
|
|
||||||
if (status == ERROR_SUCCESS)
|
if (status == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
if (RegQueryValueEx(hKey, _T("FramesPerSecond"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
if (RegQueryValueEx(hKey, _T("FramesPerSecond"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||||
wfi->framesPerSecond = dwValue;
|
wfi->framesPerSecond = dwValue;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
|
||||||
|
//Set input toggle
|
||||||
|
wfi->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)
|
||||||
|
wfi->input_disabled = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
RegCloseKey(hKey);
|
RegCloseKey(hKey);
|
||||||
|
|
||||||
//detect windows version
|
//detect windows version
|
||||||
@ -190,6 +203,15 @@ void wf_info_peer_register(wfInfo* wfi, wfPeerContext* context)
|
|||||||
{
|
{
|
||||||
if (wf_info_lock(wfi) > 0)
|
if (wf_info_lock(wfi) > 0)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
int peerId;
|
||||||
|
if (wfi->peerCount == WF_INFO_MAXPEERS)
|
||||||
|
{
|
||||||
|
context->socketClose = TRUE;
|
||||||
|
wf_info_unlock(wfi);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
context->info = wfi;
|
context->info = wfi;
|
||||||
context->updateEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
context->updateEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
|
||||||
@ -199,12 +221,25 @@ void wf_info_peer_register(wfInfo* wfi, wfPeerContext* context)
|
|||||||
#else
|
#else
|
||||||
wf_mirror_driver_activate(wfi);
|
wf_mirror_driver_activate(wfi);
|
||||||
#endif
|
#endif
|
||||||
|
//look trhough the array of peers until an empty slot
|
||||||
|
for(i=0; i<WF_INFO_MAXPEERS; ++i)
|
||||||
|
{
|
||||||
|
//empty index will be our peer id
|
||||||
|
if (wfi->peers[i] == NULL)
|
||||||
|
{
|
||||||
|
peerId = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wfi->peers[wfi->peerCount++] = ((rdpContext*) context)->peer;
|
wfi->peers[peerId] = ((rdpContext*) context)->peer;
|
||||||
|
wfi->peers[peerId]->pId = peerId;
|
||||||
printf("Registering Peer: %d\n", wfi->peerCount);
|
wfi->peerCount++;
|
||||||
|
printf("Registering Peer: id=%d #=%d\n", peerId, wfi->peerCount);
|
||||||
|
|
||||||
wf_info_unlock(wfi);
|
wf_info_unlock(wfi);
|
||||||
|
|
||||||
|
wfreerdp_server_peer_callback_event(peerId, WF_SRV_CALLBACK_EVENT_CONNECT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,10 +247,14 @@ void wf_info_peer_unregister(wfInfo* wfi, wfPeerContext* context)
|
|||||||
{
|
{
|
||||||
if (wf_info_lock(wfi) > 0)
|
if (wf_info_lock(wfi) > 0)
|
||||||
{
|
{
|
||||||
wfi->peers[--(wfi->peerCount)] = NULL;
|
int peerId;
|
||||||
|
|
||||||
|
peerId = ((rdpContext*) context)->peer->pId;
|
||||||
|
wfi->peers[peerId] = NULL;
|
||||||
|
wfi->peerCount--;
|
||||||
CloseHandle(context->updateEvent);
|
CloseHandle(context->updateEvent);
|
||||||
|
|
||||||
printf("Unregistering Peer: %d\n", wfi->peerCount);
|
printf("Unregistering Peer: id=%d, #=%d\n", peerId, wfi->peerCount);
|
||||||
|
|
||||||
#ifdef WITH_WIN8
|
#ifdef WITH_WIN8
|
||||||
if (wfi->peerCount == 0)
|
if (wfi->peerCount == 0)
|
||||||
@ -223,6 +262,8 @@ void wf_info_peer_unregister(wfInfo* wfi, wfPeerContext* context)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
wf_info_unlock(wfi);
|
wf_info_unlock(wfi);
|
||||||
|
|
||||||
|
wfreerdp_server_peer_callback_event(peerId, WF_SRV_CALLBACK_EVENT_DISCONNECT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,9 @@
|
|||||||
|
|
||||||
#include "wf_interface.h"
|
#include "wf_interface.h"
|
||||||
|
|
||||||
|
#define WF_INFO_DEFAULT_FPS 24
|
||||||
|
#define WF_INFO_MAXPEERS 32
|
||||||
|
|
||||||
int wf_info_lock(wfInfo* wfi);
|
int wf_info_lock(wfInfo* wfi);
|
||||||
int wf_info_try_lock(wfInfo* wfi, DWORD dwMilliseconds);
|
int wf_info_try_lock(wfInfo* wfi, DWORD dwMilliseconds);
|
||||||
int wf_info_unlock(wfInfo* wfi);
|
int wf_info_unlock(wfInfo* wfi);
|
||||||
|
@ -164,3 +164,20 @@ void wf_peer_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT1
|
|||||||
wf_peer_mouse_event(input, flags, x, y);
|
wf_peer_mouse_event(input, flags, x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wf_peer_keyboard_event_dummy(rdpInput* input, UINT16 flags, UINT16 code)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void wf_peer_unicode_keyboard_event_dummy(rdpInput* input, UINT16 flags, UINT16 code)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void wf_peer_mouse_event_dummy(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void wf_peer_extended_mouse_event_dummy(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
@ -27,4 +27,10 @@ void wf_peer_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code);
|
|||||||
void wf_peer_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y);
|
void wf_peer_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y);
|
||||||
void wf_peer_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y);
|
void wf_peer_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y);
|
||||||
|
|
||||||
|
//dummy versions
|
||||||
|
void wf_peer_keyboard_event_dummy(rdpInput* input, UINT16 flags, UINT16 code);
|
||||||
|
void wf_peer_unicode_keyboard_event_dummy(rdpInput* input, UINT16 flags, UINT16 code);
|
||||||
|
void wf_peer_mouse_event_dummy(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y);
|
||||||
|
void wf_peer_extended_mouse_event_dummy(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y);
|
||||||
|
|
||||||
#endif /* WF_INPUT_H */
|
#endif /* WF_INPUT_H */
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
* FreeRDP Windows Server
|
* FreeRDP Windows Server
|
||||||
*
|
*
|
||||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||||
|
* Copyright 2012 Corey Clayton <can.of.tuna@gmail.com>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -21,15 +22,20 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#include <winpr/tchar.h>
|
#include <winpr/tchar.h>
|
||||||
#include <winpr/windows.h>
|
#include <winpr/windows.h>
|
||||||
#include <freerdp/utils/tcp.h>
|
#include <freerdp/utils/tcp.h>
|
||||||
|
#include <freerdp\listener.h>
|
||||||
|
|
||||||
#include "wf_peer.h"
|
#include "wf_peer.h"
|
||||||
#include "wf_settings.h"
|
#include "wf_settings.h"
|
||||||
|
#include "wf_info.h"
|
||||||
|
|
||||||
#include "wf_interface.h"
|
#include "wf_interface.h"
|
||||||
|
|
||||||
|
cbCallback cbEvent;
|
||||||
|
|
||||||
DWORD WINAPI wf_server_main_loop(LPVOID lpParam)
|
DWORD WINAPI wf_server_main_loop(LPVOID lpParam)
|
||||||
{
|
{
|
||||||
int i, fds;
|
int i, fds;
|
||||||
@ -38,11 +44,15 @@ DWORD WINAPI wf_server_main_loop(LPVOID lpParam)
|
|||||||
void* rfds[32];
|
void* rfds[32];
|
||||||
fd_set rfds_set;
|
fd_set rfds_set;
|
||||||
freerdp_listener* instance;
|
freerdp_listener* instance;
|
||||||
|
wfInfo* wfi;
|
||||||
|
|
||||||
|
wfi = wf_info_get_instance();
|
||||||
|
wfi->force_all_disconnect = FALSE;
|
||||||
|
|
||||||
ZeroMemory(rfds, sizeof(rfds));
|
ZeroMemory(rfds, sizeof(rfds));
|
||||||
instance = (freerdp_listener*) lpParam;
|
instance = (freerdp_listener*) lpParam;
|
||||||
|
|
||||||
while (1)
|
while(wfi->force_all_disconnect == FALSE)
|
||||||
{
|
{
|
||||||
rcount = 0;
|
rcount = 0;
|
||||||
|
|
||||||
@ -68,6 +78,7 @@ DWORD WINAPI wf_server_main_loop(LPVOID lpParam)
|
|||||||
if (max_fds == 0)
|
if (max_fds == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
select(max_fds + 1, &rfds_set, NULL, NULL, NULL);
|
select(max_fds + 1, &rfds_set, NULL, NULL, NULL);
|
||||||
|
|
||||||
if (instance->CheckFileDescriptor(instance) != TRUE)
|
if (instance->CheckFileDescriptor(instance) != TRUE)
|
||||||
@ -77,6 +88,8 @@ DWORD WINAPI wf_server_main_loop(LPVOID lpParam)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printf("wf_server_main_loop terminating\n");
|
||||||
|
|
||||||
instance->Close(instance);
|
instance->Close(instance);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -103,6 +116,13 @@ BOOL wfreerdp_server_start(wfServer* server)
|
|||||||
|
|
||||||
BOOL wfreerdp_server_stop(wfServer* server)
|
BOOL wfreerdp_server_stop(wfServer* server)
|
||||||
{
|
{
|
||||||
|
wfInfo* wfi;
|
||||||
|
|
||||||
|
wfi = wf_info_get_instance();
|
||||||
|
|
||||||
|
printf("Stopping server\n");
|
||||||
|
wfi->force_all_disconnect = TRUE;
|
||||||
|
server->instance->Close(server->instance);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,6 +140,8 @@ wfServer* wfreerdp_server_new()
|
|||||||
server->port = 3389;
|
server->port = 3389;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cbEvent = NULL;
|
||||||
|
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,3 +154,141 @@ void wfreerdp_server_free(wfServer* server)
|
|||||||
|
|
||||||
freerdp_wsa_cleanup();
|
freerdp_wsa_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FREERDP_API BOOL wfreerdp_server_is_running(wfServer* server)
|
||||||
|
{
|
||||||
|
DWORD tStatus;
|
||||||
|
BOOL bRet;
|
||||||
|
|
||||||
|
bRet = GetExitCodeThread(server->thread, &tStatus);
|
||||||
|
if (bRet == 0)
|
||||||
|
{
|
||||||
|
printf("Error in call to GetExitCodeThread\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tStatus == STILL_ACTIVE)
|
||||||
|
return TRUE;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
FREERDP_API UINT32 wfreerdp_server_num_peers()
|
||||||
|
{
|
||||||
|
wfInfo* wfi;
|
||||||
|
|
||||||
|
wfi = wf_info_get_instance();
|
||||||
|
return wfi->peerCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
FREERDP_API UINT32 wfreerdp_server_get_peer_hostname(int pId, wchar_t * dstStr)
|
||||||
|
{
|
||||||
|
wfInfo* wfi;
|
||||||
|
freerdp_peer* peer;
|
||||||
|
|
||||||
|
wfi = wf_info_get_instance();
|
||||||
|
peer = wfi->peers[pId];
|
||||||
|
|
||||||
|
|
||||||
|
if (peer)
|
||||||
|
{
|
||||||
|
UINT32 sLen;
|
||||||
|
|
||||||
|
sLen = strnlen_s(peer->hostname, 50);
|
||||||
|
swprintf(dstStr, 50, L"%hs", peer->hostname);
|
||||||
|
return sLen;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("nonexistent peer id=%d\n", pId);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
FREERDP_API BOOL wfreerdp_server_peer_is_local(int pId)
|
||||||
|
{
|
||||||
|
wfInfo* wfi;
|
||||||
|
freerdp_peer* peer;
|
||||||
|
|
||||||
|
wfi = wf_info_get_instance();
|
||||||
|
peer = wfi->peers[pId];
|
||||||
|
|
||||||
|
|
||||||
|
if (peer)
|
||||||
|
{
|
||||||
|
return peer->local;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FREERDP_API BOOL wfreerdp_server_peer_is_connected(int pId)
|
||||||
|
{
|
||||||
|
wfInfo* wfi;
|
||||||
|
freerdp_peer* peer;
|
||||||
|
|
||||||
|
wfi = wf_info_get_instance();
|
||||||
|
peer = wfi->peers[pId];
|
||||||
|
|
||||||
|
|
||||||
|
if (peer)
|
||||||
|
{
|
||||||
|
return peer->connected;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FREERDP_API BOOL wfreerdp_server_peer_is_activated(int pId)
|
||||||
|
{
|
||||||
|
wfInfo* wfi;
|
||||||
|
freerdp_peer* peer;
|
||||||
|
|
||||||
|
wfi = wf_info_get_instance();
|
||||||
|
peer = wfi->peers[pId];
|
||||||
|
|
||||||
|
|
||||||
|
if (peer)
|
||||||
|
{
|
||||||
|
return peer->activated;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FREERDP_API BOOL wfreerdp_server_peer_is_authenticated(int pId)
|
||||||
|
{
|
||||||
|
wfInfo* wfi;
|
||||||
|
freerdp_peer* peer;
|
||||||
|
|
||||||
|
wfi = wf_info_get_instance();
|
||||||
|
peer = wfi->peers[pId];
|
||||||
|
|
||||||
|
|
||||||
|
if (peer)
|
||||||
|
{
|
||||||
|
return peer->authenticated;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FREERDP_API void wfreerdp_server_register_callback_event(cbCallback cb)
|
||||||
|
{
|
||||||
|
cbEvent = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wfreerdp_server_peer_callback_event(int pId, UINT32 eType)
|
||||||
|
{
|
||||||
|
if (cbEvent)
|
||||||
|
cbEvent(pId, eType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
* FreeRDP: A Remote Desktop Protocol Client
|
||||||
* FreeRDP Windows Server
|
* FreeRDP Windows Server
|
||||||
*
|
*
|
||||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||||
|
* Copyright 2012 Corey Clayton <can.of.tuna@gmail.com>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -30,6 +31,11 @@
|
|||||||
#include <freerdp/codec/rfx.h>
|
#include <freerdp/codec/rfx.h>
|
||||||
#include <freerdp/server/rdpsnd.h>
|
#include <freerdp/server/rdpsnd.h>
|
||||||
|
|
||||||
|
#define WF_SRV_CALLBACK_EVENT_CONNECT 1
|
||||||
|
#define WF_SRV_CALLBACK_EVENT_DISCONNECT 2
|
||||||
|
#define WF_SRV_CALLBACK_EVENT_ACTIVATE 4
|
||||||
|
#define WF_SRV_CALLBACK_EVENT_AUTH 8
|
||||||
|
|
||||||
typedef struct wf_info wfInfo;
|
typedef struct wf_info wfInfo;
|
||||||
typedef struct wf_peer_context wfPeerContext;
|
typedef struct wf_peer_context wfPeerContext;
|
||||||
|
|
||||||
@ -51,6 +57,9 @@ struct wf_info
|
|||||||
BOOL mirrorDriverActive;
|
BOOL mirrorDriverActive;
|
||||||
UINT framesWaiting;
|
UINT framesWaiting;
|
||||||
|
|
||||||
|
HANDLE snd_mutex;
|
||||||
|
BOOL snd_stop;
|
||||||
|
|
||||||
RECT invalid;
|
RECT invalid;
|
||||||
HANDLE mutex;
|
HANDLE mutex;
|
||||||
BOOL updatePending;
|
BOOL updatePending;
|
||||||
@ -61,6 +70,9 @@ struct wf_info
|
|||||||
unsigned long lastUpdate;
|
unsigned long lastUpdate;
|
||||||
unsigned long nextUpdate;
|
unsigned long nextUpdate;
|
||||||
SURFACE_BITS_COMMAND cmd;
|
SURFACE_BITS_COMMAND cmd;
|
||||||
|
|
||||||
|
BOOL input_disabled;
|
||||||
|
BOOL force_all_disconnect;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wf_peer_context
|
struct wf_peer_context
|
||||||
@ -87,10 +99,25 @@ struct wf_server
|
|||||||
};
|
};
|
||||||
typedef struct wf_server wfServer;
|
typedef struct wf_server wfServer;
|
||||||
|
|
||||||
|
typedef void (__stdcall* cbCallback) (int, UINT32);
|
||||||
|
|
||||||
FREERDP_API BOOL wfreerdp_server_start(wfServer* server);
|
FREERDP_API BOOL wfreerdp_server_start(wfServer* server);
|
||||||
FREERDP_API BOOL wfreerdp_server_stop(wfServer* server);
|
FREERDP_API BOOL wfreerdp_server_stop(wfServer* server);
|
||||||
|
|
||||||
FREERDP_API wfServer* wfreerdp_server_new();
|
FREERDP_API wfServer* wfreerdp_server_new();
|
||||||
FREERDP_API void wfreerdp_server_free(wfServer* server);
|
FREERDP_API void wfreerdp_server_free(wfServer* server);
|
||||||
|
|
||||||
|
FREERDP_API BOOL wfreerdp_server_is_running(wfServer* server);
|
||||||
|
|
||||||
|
FREERDP_API UINT32 wfreerdp_server_num_peers();
|
||||||
|
FREERDP_API UINT32 wfreerdp_server_get_peer_hostname(int pId, wchar_t * dstStr);
|
||||||
|
FREERDP_API BOOL wfreerdp_server_peer_is_local(int pId);
|
||||||
|
FREERDP_API BOOL wfreerdp_server_peer_is_connected(int pId);
|
||||||
|
FREERDP_API BOOL wfreerdp_server_peer_is_activated(int pId);
|
||||||
|
FREERDP_API BOOL wfreerdp_server_peer_is_authenticated(int pId);
|
||||||
|
|
||||||
|
FREERDP_API void wfreerdp_server_register_callback_event(cbCallback cb);
|
||||||
|
|
||||||
|
void wfreerdp_server_peer_callback_event(int pId, UINT32 eType);
|
||||||
|
|
||||||
#endif /* WF_INTERFACE_H */
|
#endif /* WF_INTERFACE_H */
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
* FreeRDP: A Remote Desktop Protocol Client
|
||||||
* FreeRDP Windows Server
|
* FreeRDP Windows Server
|
||||||
*
|
*
|
||||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||||
|
* Copyright 2012 Corey Clayton <can.of.tuna@gmail.com>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -50,7 +51,13 @@ void wf_peer_context_free(freerdp_peer* client, wfPeerContext* context)
|
|||||||
wf_info_peer_unregister(context->info, context);
|
wf_info_peer_unregister(context->info, context);
|
||||||
|
|
||||||
if (context->rdpsnd)
|
if (context->rdpsnd)
|
||||||
|
{
|
||||||
|
printf("snd_free\n");
|
||||||
|
wf_rdpsnd_lock();
|
||||||
|
context->info->snd_stop = TRUE;
|
||||||
rdpsnd_server_context_free(context->rdpsnd);
|
rdpsnd_server_context_free(context->rdpsnd);
|
||||||
|
wf_rdpsnd_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
WTSDestroyVirtualChannelManager(context->vcm);
|
WTSDestroyVirtualChannelManager(context->vcm);
|
||||||
}
|
}
|
||||||
@ -118,6 +125,8 @@ BOOL wf_peer_activate(freerdp_peer* client)
|
|||||||
client->activated = TRUE;
|
client->activated = TRUE;
|
||||||
wf_update_peer_activate(wfi, context);
|
wf_update_peer_activate(wfi, context);
|
||||||
|
|
||||||
|
wfreerdp_server_peer_callback_event(((rdpContext*) context)->peer->pId, WF_SRV_CALLBACK_EVENT_ACTIVATE);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,6 +140,8 @@ BOOL wf_peer_logon(freerdp_peer* client, SEC_WINNT_AUTH_IDENTITY* identity, BOOL
|
|||||||
identity->User, identity->Domain, identity->Password);
|
identity->User, identity->Domain, identity->Password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wfreerdp_server_peer_callback_event(((rdpContext*) client->context)->peer->pId, WF_SRV_CALLBACK_EVENT_AUTH);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,7 +250,20 @@ DWORD WINAPI wf_peer_main_loop(LPVOID lpParam)
|
|||||||
client->Initialize(client);
|
client->Initialize(client);
|
||||||
context = (wfPeerContext*) client->context;
|
context = (wfPeerContext*) client->context;
|
||||||
|
|
||||||
|
if (context->socketClose)
|
||||||
|
return 0;
|
||||||
|
|
||||||
wfi = context->info;
|
wfi = context->info;
|
||||||
|
|
||||||
|
if (wfi->input_disabled == TRUE)
|
||||||
|
{
|
||||||
|
printf("client input is disabled\n");
|
||||||
|
client->input->KeyboardEvent = wf_peer_keyboard_event_dummy;
|
||||||
|
client->input->UnicodeKeyboardEvent = wf_peer_unicode_keyboard_event_dummy;
|
||||||
|
client->input->MouseEvent = wf_peer_mouse_event_dummy;
|
||||||
|
client->input->ExtendedMouseEvent = wf_peer_extended_mouse_event_dummy;
|
||||||
|
}
|
||||||
|
|
||||||
context->socketEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
context->socketEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
printf("socketEvent created\n");
|
printf("socketEvent created\n");
|
||||||
|
|
||||||
@ -288,6 +312,13 @@ DWORD WINAPI wf_peer_main_loop(LPVOID lpParam)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//force disconnect
|
||||||
|
if(wfi->force_all_disconnect == TRUE)
|
||||||
|
{
|
||||||
|
printf("Forcing Disconnect -> ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* FIXME: we should wait on this, instead of calling it every time */
|
/* FIXME: we should wait on this, instead of calling it every time */
|
||||||
if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE)
|
if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE)
|
||||||
break;
|
break;
|
||||||
|
@ -24,9 +24,29 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <winpr\windows.h>
|
||||||
|
#define CINTERFACE
|
||||||
|
#include <mmsystem.h>
|
||||||
|
#include <dsound.h>
|
||||||
|
|
||||||
#include <freerdp/server/rdpsnd.h>
|
#include <freerdp/server/rdpsnd.h>
|
||||||
|
|
||||||
#include "wf_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 capturePos;
|
||||||
|
|
||||||
|
#define BYTESPERSEC 176400
|
||||||
|
|
||||||
|
//FIXME support multiple clients
|
||||||
|
wfPeerContext* latestPeer;
|
||||||
|
|
||||||
static const rdpsndFormat test_audio_formats[] =
|
static const rdpsndFormat test_audio_formats[] =
|
||||||
{
|
{
|
||||||
@ -44,11 +64,107 @@ static const rdpsndFormat test_audio_formats[] =
|
|||||||
|
|
||||||
static void wf_peer_rdpsnd_activated(rdpsnd_server_context* context)
|
static void wf_peer_rdpsnd_activated(rdpsnd_server_context* context)
|
||||||
{
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
LPDIRECTSOUNDCAPTUREBUFFER pDSCB;
|
||||||
|
WAVEFORMATEX wfx = {WAVE_FORMAT_PCM, 2, 44100, BYTESPERSEC, 4, 16, 0};
|
||||||
|
|
||||||
|
|
||||||
printf("RDPSND Activated\n");
|
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);
|
||||||
|
capturePos = 0;
|
||||||
|
|
||||||
|
CreateThread(NULL, 0, wf_rdpsnd_thread, latestPeer, 0, NULL);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int wf_rdpsnd_lock()
|
||||||
|
{
|
||||||
|
DWORD dRes;
|
||||||
|
wfInfo* wfi;
|
||||||
|
|
||||||
|
wfi = wf_info_get_instance();
|
||||||
|
|
||||||
|
dRes = WaitForSingleObject(wfi->snd_mutex, INFINITE);
|
||||||
|
|
||||||
|
switch (dRes)
|
||||||
|
{
|
||||||
|
case WAIT_ABANDONED:
|
||||||
|
case WAIT_OBJECT_0:
|
||||||
|
return TRUE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WAIT_TIMEOUT:
|
||||||
|
return FALSE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WAIT_FAILED:
|
||||||
|
printf("wf_rdpsnd_lock failed with 0x%08X\n", GetLastError());
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wf_rdpsnd_unlock()
|
||||||
|
{
|
||||||
|
wfInfo* wfi;
|
||||||
|
|
||||||
|
wfi = wf_info_get_instance();
|
||||||
|
|
||||||
|
if (ReleaseMutex(wfi->snd_mutex) == 0)
|
||||||
|
{
|
||||||
|
printf("wf_rdpsnd_unlock failed with 0x%08X\n", GetLastError());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL wf_peer_rdpsnd_init(wfPeerContext* context)
|
BOOL wf_peer_rdpsnd_init(wfPeerContext* context)
|
||||||
{
|
{
|
||||||
|
wfInfo* wfi;
|
||||||
|
|
||||||
|
wfi = wf_info_get_instance();
|
||||||
|
|
||||||
|
wfi->snd_mutex = CreateMutex(NULL, FALSE, NULL);
|
||||||
context->rdpsnd = rdpsnd_server_context_new(context->vcm);
|
context->rdpsnd = rdpsnd_server_context_new(context->vcm);
|
||||||
context->rdpsnd->data = context;
|
context->rdpsnd->data = context;
|
||||||
|
|
||||||
@ -65,5 +181,121 @@ BOOL wf_peer_rdpsnd_init(wfPeerContext* context)
|
|||||||
|
|
||||||
context->rdpsnd->Initialize(context->rdpsnd);
|
context->rdpsnd->Initialize(context->rdpsnd);
|
||||||
|
|
||||||
|
latestPeer = context;
|
||||||
|
wfi->snd_stop = FALSE;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DWORD WINAPI wf_rdpsnd_thread(LPVOID lpParam)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
DWORD beg, end;
|
||||||
|
DWORD diff, rate;
|
||||||
|
wfPeerContext* context;
|
||||||
|
wfInfo* wfi;
|
||||||
|
|
||||||
|
wfi = wf_info_get_instance();
|
||||||
|
|
||||||
|
context = (wfPeerContext*)lpParam;
|
||||||
|
rate = 1000 / 5;
|
||||||
|
|
||||||
|
_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)
|
||||||
|
{
|
||||||
|
VOID* pbCaptureData = NULL;
|
||||||
|
DWORD dwCaptureLength;
|
||||||
|
VOID* pbCaptureData2 = NULL;
|
||||||
|
DWORD dwCaptureLength2;
|
||||||
|
VOID* pbPlayData = NULL;
|
||||||
|
DWORD dwReadPos;
|
||||||
|
LONG lLockSize;
|
||||||
|
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 - capturePos;//dscbd.dwBufferBytes;
|
||||||
|
if (lLockSize < 0) lLockSize += dscbd.dwBufferBytes;
|
||||||
|
|
||||||
|
if (lLockSize == 0)
|
||||||
|
{
|
||||||
|
wf_rdpsnd_unlock();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
hr = capBuf->lpVtbl->Lock(capBuf, capturePos, 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
|
||||||
|
capturePos += dwCaptureLength;
|
||||||
|
capturePos %= dscbd.dwBufferBytes;
|
||||||
|
capturePos += dwCaptureLength2;
|
||||||
|
capturePos %= dscbd.dwBufferBytes;
|
||||||
|
|
||||||
|
wf_rdpsnd_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
end = GetTickCount();
|
||||||
|
diff = end - beg;
|
||||||
|
|
||||||
|
if (diff < rate)
|
||||||
|
{
|
||||||
|
Sleep(rate - diff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_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"));
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -26,7 +26,11 @@
|
|||||||
|
|
||||||
#include "wf_interface.h"
|
#include "wf_interface.h"
|
||||||
|
|
||||||
|
int wf_rdpsnd_lock();
|
||||||
|
int wf_rdpsnd_unlock();
|
||||||
BOOL wf_peer_rdpsnd_init(wfPeerContext* context);
|
BOOL wf_peer_rdpsnd_init(wfPeerContext* context);
|
||||||
|
|
||||||
|
DWORD WINAPI wf_rdpsnd_thread(LPVOID lpParam);
|
||||||
|
|
||||||
#endif /* WF_RDPSND_H */
|
#endif /* WF_RDPSND_H */
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
* FreeRDP: A Remote Desktop Protocol Client
|
||||||
* FreeRDP Windows Server
|
* FreeRDP Windows Server
|
||||||
*
|
*
|
||||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||||
|
* Copyright 2012 Corey Clayton <can.of.tuna@gmail.com>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -37,6 +38,7 @@
|
|||||||
DWORD WINAPI wf_update_thread(LPVOID lpParam)
|
DWORD WINAPI wf_update_thread(LPVOID lpParam)
|
||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
|
int peerindex;
|
||||||
DWORD fps;
|
DWORD fps;
|
||||||
wfInfo* wfi;
|
wfInfo* wfi;
|
||||||
DWORD beg, end;
|
DWORD beg, end;
|
||||||
@ -62,16 +64,20 @@ DWORD WINAPI wf_update_thread(LPVOID lpParam)
|
|||||||
wf_update_encode(wfi);
|
wf_update_encode(wfi);
|
||||||
|
|
||||||
//printf("Start of parallel sending\n");
|
//printf("Start of parallel sending\n");
|
||||||
|
index = 0;
|
||||||
for (index = 0; index < wfi->peerCount; index++)
|
for (peerindex = 0; peerindex < wfi->peerCount; peerindex++)
|
||||||
{
|
{
|
||||||
if (wfi->peers[index]->activated)
|
for (; index < WF_INFO_MAXPEERS; index++)
|
||||||
|
{
|
||||||
|
if (wfi->peers[index] && wfi->peers[index]->activated)
|
||||||
{
|
{
|
||||||
//printf("Setting event for %d of %d\n", index + 1, wfi->activePeerCount);
|
//printf("Setting event for %d of %d\n", index + 1, wfi->activePeerCount);
|
||||||
SetEvent(((wfPeerContext*) wfi->peers[index]->context)->updateEvent);
|
SetEvent(((wfPeerContext*) wfi->peers[index]->context)->updateEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
for (index = 0; index < wfi->activePeerCount; index++)
|
for (index = 0; index < wfi->activePeerCount; index++)
|
||||||
{
|
{
|
||||||
//printf("Waiting for %d of %d\n", index + 1, wfi->activePeerCount);
|
//printf("Waiting for %d of %d\n", index + 1, wfi->activePeerCount);
|
||||||
|
Loading…
Reference in New Issue
Block a user