channels/rdpsnd: decouple rdpsnd from svc_plugin

This commit is contained in:
Marc-André Moreau 2013-10-19 16:20:31 -04:00
parent dbbb364caf
commit bd64e616de
2 changed files with 289 additions and 50 deletions

View File

@ -35,6 +35,8 @@
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/print.h>
#include <winpr/thread.h>
#include <winpr/stream.h>
#include <winpr/cmdline.h>
#include <winpr/sysinfo.h>
#include <winpr/collections.h>
@ -42,9 +44,8 @@
#include <freerdp/types.h>
#include <freerdp/addin.h>
#include <freerdp/constants.h>
#include <winpr/stream.h>
#include <freerdp/utils/debug.h>
#include <freerdp/utils/signal.h>
#include <freerdp/utils/svc_plugin.h>
#include "rdpsnd_main.h"
@ -52,9 +53,16 @@
struct rdpsnd_plugin
{
rdpSvcPlugin plugin;
CHANNEL_DEF channelDef;
CHANNEL_ENTRY_POINTS_EX channelEntryPoints;
HANDLE thread;
wStream* data_in;
void* InitHandle;
UINT32 OpenHandle;
wMessagePipe* MsgPipe;
HANDLE ScheduleThread;
wMessageQueue* queue;
BYTE cBlockNo;
@ -135,7 +143,7 @@ void rdpsnd_send_quality_mode_pdu(rdpsndPlugin* rdpsnd)
Stream_Write_UINT16(pdu, HIGH_QUALITY); /* wQualityMode */
Stream_Write_UINT16(pdu, 0); /* Reserved */
svc_plugin_send((rdpSvcPlugin*) rdpsnd, pdu);
rdpsnd_virtual_channel_write(rdpsnd, pdu);
}
void rdpsnd_select_supported_audio_formats(rdpsndPlugin* rdpsnd)
@ -251,7 +259,7 @@ void rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd)
Stream_Write(pdu, clientFormat->data, clientFormat->cbSize);
}
svc_plugin_send((rdpSvcPlugin*) rdpsnd, pdu);
rdpsnd_virtual_channel_write(rdpsnd, pdu);
}
void rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream* s)
@ -316,7 +324,7 @@ void rdpsnd_send_training_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, U
Stream_Write_UINT16(pdu, wTimeStamp);
Stream_Write_UINT16(pdu, wPackSize);
svc_plugin_send((rdpSvcPlugin*) rdpsnd, pdu);
rdpsnd_virtual_channel_write(rdpsnd, pdu);
}
static void rdpsnd_recv_training_pdu(rdpsndPlugin* rdpsnd, wStream* s)
@ -382,7 +390,7 @@ void rdpsnd_send_wave_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, BYTE
Stream_Write_UINT8(pdu, cConfirmedBlockNo); /* cConfirmedBlockNo */
Stream_Write_UINT8(pdu, 0); /* bPad */
svc_plugin_send((rdpSvcPlugin*) rdpsnd, pdu);
rdpsnd_virtual_channel_write(rdpsnd, pdu);
}
static void rdpsnd_device_send_wave_confirm_pdu(rdpsndDevicePlugin* device, RDPSND_WAVE* wave)
@ -454,8 +462,6 @@ static void rdpsnd_recv_wave_pdu(rdpsndPlugin* rdpsnd, wStream* s)
static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd)
{
DEBUG_SVC("server closes.");
if (rdpsnd->device)
{
IFCALL(rdpsnd->device->Close, rdpsnd->device);
@ -469,7 +475,6 @@ static void rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s)
UINT32 dwVolume;
Stream_Read_UINT32(s, dwVolume);
DEBUG_SVC("dwVolume 0x%X", dwVolume);
if (rdpsnd->device)
{
@ -477,11 +482,10 @@ static void rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s)
}
}
static void rdpsnd_recv_pdu(rdpSvcPlugin* plugin, wStream* s)
static void rdpsnd_recv_pdu(rdpsndPlugin* rdpsnd, wStream* s)
{
BYTE msgType;
UINT16 BodySize;
rdpsndPlugin* rdpsnd = (rdpsndPlugin*) plugin;
if (rdpsnd->expectingWave)
{
@ -646,20 +650,18 @@ static void rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args)
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
}
static void rdpsnd_process_connect(rdpSvcPlugin* plugin)
static void rdpsnd_process_connect(rdpsndPlugin* rdpsnd)
{
ADDIN_ARGV* args;
rdpsndPlugin* rdpsnd = (rdpsndPlugin*) plugin;
DEBUG_SVC("connecting");
rdpsnd->latency = -1;
rdpsnd->queue = MessageQueue_New();
rdpsnd->thread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) rdpsnd_schedule_thread,
(void*) plugin, 0, NULL);
args = (ADDIN_ARGV*) plugin->channel_entry_points.pExtendedData;
rdpsnd->ScheduleThread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) rdpsnd_schedule_thread,
(void*) rdpsnd, 0, NULL);
args = (ADDIN_ARGV*) rdpsnd->channelEntryPoints.pExtendedData;
if (args)
rdpsnd_process_addin_args(rdpsnd, args);
@ -733,23 +735,16 @@ static void rdpsnd_process_connect(rdpSvcPlugin* plugin)
}
}
static void rdpsnd_process_event(rdpSvcPlugin* plugin, wMessage* event)
static void rdpsnd_process_terminate(rdpsndPlugin* rdpsnd)
{
freerdp_event_free(event);
}
static void rdpsnd_process_terminate(rdpSvcPlugin* plugin)
{
rdpsndPlugin* rdpsnd = (rdpsndPlugin*) plugin;
if (rdpsnd->device)
IFCALL(rdpsnd->device->Free, rdpsnd->device);
MessageQueue_PostQuit(rdpsnd->queue, 0);
WaitForSingleObject(rdpsnd->thread, INFINITE);
WaitForSingleObject(rdpsnd->ScheduleThread, INFINITE);
MessageQueue_Free(rdpsnd->queue);
CloseHandle(rdpsnd->thread);
CloseHandle(rdpsnd->ScheduleThread);
if (rdpsnd->subsystem)
free(rdpsnd->subsystem);
@ -766,26 +761,253 @@ static void rdpsnd_process_terminate(rdpSvcPlugin* plugin)
rdpsnd->ClientFormats = NULL;
}
/****************************************************************************************/
static wListDictionary* g_InitHandles;
static wListDictionary* g_OpenHandles;
void rdpsnd_add_init_handle_data(void* pInitHandle, void* pUserData)
{
if (!g_InitHandles)
g_InitHandles = ListDictionary_New(TRUE);
ListDictionary_Add(g_InitHandles, pInitHandle, pUserData);
}
void* rdpsnd_get_init_handle_data(void* pInitHandle)
{
void* pUserData = NULL;
pUserData = ListDictionary_GetItemValue(g_InitHandles, pInitHandle);
return pUserData;
}
void rdpsnd_remove_init_handle_data(void* pInitHandle)
{
ListDictionary_Remove(g_InitHandles, pInitHandle);
}
void rdpsnd_add_open_handle_data(DWORD openHandle, void* pUserData)
{
void* pOpenHandle = (void*) (size_t) openHandle;
if (!g_OpenHandles)
g_OpenHandles = ListDictionary_New(TRUE);
ListDictionary_Add(g_OpenHandles, pOpenHandle, pUserData);
}
void* rdpsnd_get_open_handle_data(DWORD openHandle)
{
void* pUserData = NULL;
void* pOpenHandle = (void*) (size_t) openHandle;
pUserData = ListDictionary_GetItemValue(g_OpenHandles, pOpenHandle);
return pUserData;
}
void rdpsnd_remove_open_handle_data(DWORD openHandle)
{
void* pOpenHandle = (void*) (size_t) openHandle;
ListDictionary_Remove(g_OpenHandles, pOpenHandle);
}
int rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s)
{
UINT32 status = 0;
if (!rdpsnd)
status = CHANNEL_RC_BAD_INIT_HANDLE;
else
status = rdpsnd->channelEntryPoints.pVirtualChannelWrite(rdpsnd->OpenHandle,
Stream_Buffer(s), Stream_GetPosition(s), s);
if (status != CHANNEL_RC_OK)
{
Stream_Free(s, TRUE);
fprintf(stderr, "rdpdr_virtual_channel_write: VirtualChannelWrite failed %d\n", status);
}
return status;
}
static void rdpsnd_virtual_channel_event_data_received(rdpsndPlugin* plugin,
void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags)
{
wStream* s;
if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
{
return;
}
if (dataFlags & CHANNEL_FLAG_FIRST)
{
if (plugin->data_in != NULL)
Stream_Free(plugin->data_in, TRUE);
plugin->data_in = Stream_New(NULL, totalLength);
}
s = plugin->data_in;
Stream_EnsureRemainingCapacity(s, (int) dataLength);
Stream_Write(s, pData, dataLength);
if (dataFlags & CHANNEL_FLAG_LAST)
{
if (Stream_Capacity(s) != Stream_GetPosition(s))
{
fprintf(stderr, "rdpsnd_virtual_channel_event_data_received: read error\n");
}
plugin->data_in = NULL;
Stream_SealLength(s);
Stream_SetPosition(s, 0);
MessageQueue_Post(plugin->MsgPipe->In, NULL, 0, (void*) s, NULL);
}
}
static void rdpsnd_virtual_channel_open_event(UINT32 openHandle, UINT32 event,
void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags)
{
rdpsndPlugin* plugin;
plugin = (rdpsndPlugin*) rdpsnd_get_open_handle_data(openHandle);
if (!plugin)
{
fprintf(stderr, "rdpsnd_virtual_channel_open_event: error no match\n");
return;
}
switch (event)
{
case CHANNEL_EVENT_DATA_RECEIVED:
rdpsnd_virtual_channel_event_data_received(plugin, pData, dataLength, totalLength, dataFlags);
break;
case CHANNEL_EVENT_WRITE_COMPLETE:
Stream_Free((wStream*) pData, TRUE);
break;
case CHANNEL_EVENT_USER:
break;
}
}
static void* rdpsnd_virtual_channel_client_thread(void* arg)
{
wStream* data;
wMessage message;
rdpsndPlugin* plugin = (rdpsndPlugin*) arg;
rdpsnd_process_connect(plugin);
while (1)
{
if (!MessageQueue_Wait(plugin->MsgPipe->In))
break;
if (MessageQueue_Peek(plugin->MsgPipe->In, &message, TRUE))
{
if (message.id == WMQ_QUIT)
break;
if (message.id == 0)
{
data = (wStream*) message.wParam;
rdpsnd_recv_pdu(plugin, data);
}
}
}
ExitThread(0);
return NULL;
}
static void rdpsnd_virtual_channel_event_connected(rdpsndPlugin* plugin, void* pData, UINT32 dataLength)
{
UINT32 status;
status = plugin->channelEntryPoints.pVirtualChannelOpen(plugin->InitHandle,
&plugin->OpenHandle, plugin->channelDef.name, rdpsnd_virtual_channel_open_event);
rdpsnd_add_open_handle_data(plugin->OpenHandle, plugin);
if (status != CHANNEL_RC_OK)
{
fprintf(stderr, "rdpsnd_virtual_channel_event_connected: open failed: status: %d\n", status);
return;
}
plugin->MsgPipe = MessagePipe_New();
plugin->thread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) rdpsnd_virtual_channel_client_thread, (void*) plugin, 0, NULL);
}
static void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* plugin)
{
MessagePipe_PostQuit(plugin->MsgPipe, 0);
WaitForSingleObject(plugin->thread, INFINITE);
MessagePipe_Free(plugin->MsgPipe);
CloseHandle(plugin->thread);
plugin->channelEntryPoints.pVirtualChannelClose(plugin->OpenHandle);
if (plugin->data_in)
{
Stream_Free(plugin->data_in, TRUE);
plugin->data_in = NULL;
}
rdpsnd_process_terminate(plugin);
rdpsnd_remove_open_handle_data(plugin->OpenHandle);
rdpsnd_remove_init_handle_data(plugin->InitHandle);
}
static void rdpsnd_virtual_channel_init_event(void* pInitHandle, UINT32 event, void* pData, UINT32 dataLength)
{
rdpsndPlugin* plugin;
plugin = (rdpsndPlugin*) rdpsnd_get_init_handle_data(pInitHandle);
if (!plugin)
{
fprintf(stderr, "rdpsnd_virtual_channel_init_event: error no match\n");
return;
}
switch (event)
{
case CHANNEL_EVENT_CONNECTED:
rdpsnd_virtual_channel_event_connected(plugin, pData, dataLength);
break;
case CHANNEL_EVENT_DISCONNECTED:
break;
case CHANNEL_EVENT_TERMINATED:
rdpsnd_virtual_channel_event_terminated(plugin);
break;
}
}
/* rdpsnd is always built-in */
#define VirtualChannelEntry rdpsnd_VirtualChannelEntry
int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
{
rdpsndPlugin* _p;
rdpsndPlugin* rdpsnd;
_p = (rdpsndPlugin*) malloc(sizeof(rdpsndPlugin));
ZeroMemory(_p, sizeof(rdpsndPlugin));
rdpsnd = (rdpsndPlugin*) malloc(sizeof(rdpsndPlugin));
_p->plugin.channel_def.options =
CHANNEL_OPTION_INITIALIZED |
CHANNEL_OPTION_ENCRYPT_RDP;
strcpy(_p->plugin.channel_def.name, "rdpsnd");
_p->plugin.connect_callback = rdpsnd_process_connect;
_p->plugin.receive_callback = rdpsnd_recv_pdu;
_p->plugin.event_callback = rdpsnd_process_event;
_p->plugin.terminate_callback = rdpsnd_process_terminate;
if (rdpsnd)
{
ZeroMemory(rdpsnd, sizeof(rdpsndPlugin));
#if !defined(_WIN32) && !defined(ANDROID)
{
@ -796,7 +1018,19 @@ int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
}
#endif
svc_plugin_init((rdpSvcPlugin*) _p, pEntryPoints);
rdpsnd->channelDef.options =
CHANNEL_OPTION_INITIALIZED |
CHANNEL_OPTION_ENCRYPT_RDP;
strcpy(rdpsnd->channelDef.name, "rdpsnd");
CopyMemory(&(rdpsnd->channelEntryPoints), pEntryPoints, pEntryPoints->cbSize);
rdpsnd->channelEntryPoints.pVirtualChannelInit(&rdpsnd->InitHandle,
&rdpsnd->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, rdpsnd_virtual_channel_init_event);
rdpsnd_add_init_handle_data(rdpsnd->InitHandle, (void*) rdpsnd);
}
return 1;
}

View File

@ -21,6 +21,9 @@
#ifndef __RDPSND_MAIN_H
#define __RDPSND_MAIN_H
#include <freerdp/api.h>
#include <freerdp/svc.h>
#include <freerdp/addin.h>
#include <freerdp/client/rdpsnd.h>
#if defined(WITH_DEBUG_SND)
@ -29,4 +32,6 @@
#define DEBUG_SND(fmt, ...) do { } while (0)
#endif
int rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s);
#endif /* __RDPSND_MAIN_H */