Updated CMake channel detection
* Now both, dynamic and static channel entries can be defined by a single channel. * Added better logging to distinguish between static and dynamic channel messages.
This commit is contained in:
Родитель
da354feed0
Коммит
4eb4f58fbb
|
@ -33,26 +33,28 @@ set(CLIENT_STATIC_TYPEDEFS "${CLIENT_STATIC_TYPEDEFS}typedef UINT (*static_addin
|
|||
|
||||
foreach(STATIC_ENTRY ${CHANNEL_STATIC_CLIENT_ENTRIES})
|
||||
foreach(STATIC_MODULE ${CHANNEL_STATIC_CLIENT_MODULES})
|
||||
if(${${STATIC_MODULE}_CLIENT_ENTRY} STREQUAL ${STATIC_ENTRY})
|
||||
set(STATIC_MODULE_NAME ${${STATIC_MODULE}_CLIENT_NAME})
|
||||
set(STATIC_MODULE_CHANNEL ${${STATIC_MODULE}_CLIENT_CHANNEL})
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${STATIC_MODULE_NAME})
|
||||
foreach(ENTRY ${${STATIC_MODULE}_CLIENT_ENTRY})
|
||||
if(${ENTRY} STREQUAL ${STATIC_ENTRY})
|
||||
set(STATIC_MODULE_NAME ${${STATIC_MODULE}_CLIENT_NAME})
|
||||
set(STATIC_MODULE_CHANNEL ${${STATIC_MODULE}_CLIENT_CHANNEL})
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${STATIC_MODULE_NAME})
|
||||
|
||||
set(ENTRY_POINT_NAME "${STATIC_MODULE_CHANNEL}_${${STATIC_MODULE}_CLIENT_ENTRY}")
|
||||
if(${${STATIC_MODULE}_CLIENT_ENTRY} STREQUAL "VirtualChannelEntry")
|
||||
set(ENTRY_POINT_IMPORT "extern BOOL VCAPITYPE ${ENTRY_POINT_NAME}(PCHANNEL_ENTRY_POINTS);")
|
||||
elseif(${${STATIC_MODULE}_CLIENT_ENTRY} STREQUAL "VirtualChannelEntryEx")
|
||||
set(ENTRY_POINT_IMPORT "extern BOOL VCAPITYPE ${ENTRY_POINT_NAME}(PCHANNEL_ENTRY_POINTS,PVOID);")
|
||||
elseif(${${STATIC_MODULE}_CLIENT_ENTRY} MATCHES "DVCPluginEntry$")
|
||||
set(ENTRY_POINT_IMPORT "extern UINT ${ENTRY_POINT_NAME}(IDRDYNVC_ENTRY_POINTS* pEntryPoints);")
|
||||
elseif(${${STATIC_MODULE}_CLIENT_ENTRY} MATCHES "DeviceServiceEntry$")
|
||||
set(ENTRY_POINT_IMPORT "extern UINT ${ENTRY_POINT_NAME}(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints);")
|
||||
else()
|
||||
set(ENTRY_POINT_IMPORT "extern UINT ${ENTRY_POINT_NAME}(void);")
|
||||
set(ENTRY_POINT_NAME "${STATIC_MODULE_CHANNEL}_${ENTRY}")
|
||||
if(${ENTRY} STREQUAL "VirtualChannelEntry")
|
||||
set(ENTRY_POINT_IMPORT "extern BOOL VCAPITYPE ${ENTRY_POINT_NAME}(PCHANNEL_ENTRY_POINTS);")
|
||||
elseif(${ENTRY} STREQUAL "VirtualChannelEntryEx")
|
||||
set(ENTRY_POINT_IMPORT "extern BOOL VCAPITYPE ${ENTRY_POINT_NAME}(PCHANNEL_ENTRY_POINTS,PVOID);")
|
||||
elseif(${ENTRY} MATCHES "DVCPluginEntry$")
|
||||
set(ENTRY_POINT_IMPORT "extern UINT ${ENTRY_POINT_NAME}(IDRDYNVC_ENTRY_POINTS* pEntryPoints);")
|
||||
elseif(${ENTRY} MATCHES "DeviceServiceEntry$")
|
||||
set(ENTRY_POINT_IMPORT "extern UINT ${ENTRY_POINT_NAME}(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints);")
|
||||
else()
|
||||
set(ENTRY_POINT_IMPORT "extern UINT ${ENTRY_POINT_NAME}(void);")
|
||||
endif()
|
||||
set(${STATIC_ENTRY}_IMPORTS "${${STATIC_ENTRY}_IMPORTS}\n${ENTRY_POINT_IMPORT}")
|
||||
set(${STATIC_ENTRY}_TABLE "${${STATIC_ENTRY}_TABLE}\n\t{ \"${STATIC_MODULE_CHANNEL}\", (static_entry_fkt)${ENTRY_POINT_NAME} },")
|
||||
endif()
|
||||
set(${STATIC_ENTRY}_IMPORTS "${${STATIC_ENTRY}_IMPORTS}\n${ENTRY_POINT_IMPORT}")
|
||||
set(${STATIC_ENTRY}_TABLE "${${STATIC_ENTRY}_TABLE}\n\t{ \"${STATIC_MODULE_CHANNEL}\", (static_entry_fkt)${ENTRY_POINT_NAME} },")
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
|
@ -75,7 +77,7 @@ foreach(STATIC_MODULE ${CHANNEL_STATIC_CLIENT_MODULES})
|
|||
string(TOUPPER "CLIENT_${STATIC_MODULE_CHANNEL}_SUBSYSTEM_TABLE" SUBSYSTEM_TABLE_NAME)
|
||||
set(SUBSYSTEM_TABLE "const STATIC_SUBSYSTEM_ENTRY ${SUBSYSTEM_TABLE_NAME}[] =\n{")
|
||||
get_target_property(CHANNEL_SUBSYSTEMS ${STATIC_MODULE_NAME} SUBSYSTEMS)
|
||||
if(CHANNEL_SUBSYSTEMS MATCHES "NOTFOUND" OR STATIC_MODULE MATCHES "CHANNEL_RDPSNDDYN") # do not generate subsystem table for dynamic rdpsnd channel
|
||||
if(CHANNEL_SUBSYSTEMS MATCHES "NOTFOUND")
|
||||
set(CHANNEL_SUBSYSTEMS "")
|
||||
endif()
|
||||
foreach(STATIC_SUBSYSTEM ${CHANNEL_SUBSYSTEMS})
|
||||
|
@ -100,14 +102,12 @@ foreach(STATIC_MODULE ${CHANNEL_STATIC_CLIENT_MODULES})
|
|||
endforeach()
|
||||
set(SUBSYSTEM_TABLE "${SUBSYSTEM_TABLE}\n\t{ NULL, NULL, NULL }\n};")
|
||||
set(CLIENT_STATIC_SUBSYSTEM_TABLES "${CLIENT_STATIC_SUBSYSTEM_TABLES}\n${SUBSYSTEM_TABLE}")
|
||||
set(ENTRY_POINT_NAME "${STATIC_MODULE_CHANNEL}_${${STATIC_MODULE}_CLIENT_ENTRY}")
|
||||
# Little hack for dynamic channels support in rdpsnd
|
||||
if(STATIC_MODULE MATCHES "CHANNEL_RDPSNDDYN")
|
||||
set(SUBSYSTEM_TABLE_NAME "CLIENT_RDPSND_SUBSYSTEM_TABLE")
|
||||
endif()
|
||||
set(CLIENT_STATIC_ADDIN_TABLE "${CLIENT_STATIC_ADDIN_TABLE}\n\t{ \"${STATIC_MODULE_CHANNEL}\", (static_addin_fkt)${ENTRY_POINT_NAME}, ${SUBSYSTEM_TABLE_NAME} },")
|
||||
foreach(ENTRY ${${STATIC_MODULE}_CLIENT_ENTRY})
|
||||
set (ENTRY_POINT_NAME ${STATIC_MODULE_CHANNEL}_${ENTRY})
|
||||
set(CLIENT_STATIC_ADDIN_TABLE "${CLIENT_STATIC_ADDIN_TABLE}\n\t{ \"${STATIC_MODULE_CHANNEL}\", \"${ENTRY}\", (static_addin_fkt)${ENTRY_POINT_NAME}, ${SUBSYSTEM_TABLE_NAME} },")
|
||||
endforeach()
|
||||
endforeach()
|
||||
set(CLIENT_STATIC_ADDIN_TABLE "${CLIENT_STATIC_ADDIN_TABLE}\n\t{ NULL, NULL, NULL }\n};")
|
||||
set(CLIENT_STATIC_ADDIN_TABLE "${CLIENT_STATIC_ADDIN_TABLE}\n\t{ NULL, NULL, NULL, NULL }\n};")
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tables.c.in ${CMAKE_CURRENT_BINARY_DIR}/tables.c)
|
||||
|
||||
|
|
|
@ -349,13 +349,30 @@ PVIRTUALCHANNELENTRY freerdp_channels_load_static_addin_entry(LPCSTR pszName, LP
|
|||
LPCSTR pszType, DWORD dwFlags)
|
||||
{
|
||||
const STATIC_ADDIN_TABLE* table = CLIENT_STATIC_ADDIN_TABLE;
|
||||
const char* type = NULL;
|
||||
|
||||
if (!pszName)
|
||||
return NULL;
|
||||
|
||||
if (dwFlags & FREERDP_ADDIN_CHANNEL_DYNAMIC)
|
||||
type = "DVCPluginEntry";
|
||||
else if (dwFlags & FREERDP_ADDIN_CHANNEL_DEVICE)
|
||||
type = "DeviceServiceEntry";
|
||||
else if (dwFlags & FREERDP_ADDIN_CHANNEL_STATIC)
|
||||
{
|
||||
if (dwFlags & FREERDP_ADDIN_CHANNEL_ENTRYEX)
|
||||
type = "VirtualChannelEntryEx";
|
||||
else
|
||||
type = "VirtualChannelEntry";
|
||||
}
|
||||
|
||||
for (; table->name != NULL; table++)
|
||||
{
|
||||
if (strncmp(table->name, pszName, MAX_PATH) == 0)
|
||||
{
|
||||
if (type && strncmp(table->type, type, MAX_PATH))
|
||||
continue;
|
||||
|
||||
if (pszSubsystem != NULL)
|
||||
{
|
||||
const STATIC_SUBSYSTEM_ENTRY* subsystems = table->table;
|
||||
|
|
|
@ -44,6 +44,7 @@ typedef struct _STATIC_SUBSYSTEM_ENTRY STATIC_SUBSYSTEM_ENTRY;
|
|||
struct _STATIC_ADDIN_TABLE
|
||||
{
|
||||
const char* name;
|
||||
const char* type;
|
||||
UINT (*entry)();
|
||||
const STATIC_SUBSYSTEM_ENTRY* table;
|
||||
};
|
||||
|
|
|
@ -20,13 +20,6 @@ define_channel("rdpsnd")
|
|||
include_directories(common)
|
||||
add_subdirectory(common)
|
||||
|
||||
# Define dynamic entry point of sound channel
|
||||
set(CHANNEL_STATIC_CLIENT_MODULES ${CHANNEL_STATIC_CLIENT_MODULES} "CHANNEL_RDPSNDDYN")
|
||||
set(CHANNEL_RDPSNDDYN_CLIENT_NAME "rdpsnd-client" PARENT_SCOPE)
|
||||
set(CHANNEL_RDPSNDDYN_CLIENT_CHANNEL "rdpsnd_dyn" PARENT_SCOPE)
|
||||
set(CHANNEL_RDPSNDDYN_CLIENT_ENTRY "DVCPluginEntry" PARENT_SCOPE)
|
||||
set(CHANNEL_STATIC_CLIENT_ENTRIES ${CHANNEL_STATIC_CLIENT_ENTRIES} ${CHANNEL_RDPSNDDYN_CLIENT_ENTRY})
|
||||
|
||||
if(WITH_CLIENT_CHANNELS)
|
||||
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
|
||||
endif()
|
||||
|
|
|
@ -3,7 +3,7 @@ set(OPTION_DEFAULT OFF)
|
|||
set(OPTION_CLIENT_DEFAULT ON)
|
||||
set(OPTION_SERVER_DEFAULT ON)
|
||||
|
||||
define_channel_options(NAME "rdpsnd" TYPE "static"
|
||||
define_channel_options(NAME "rdpsnd" TYPE "static;dynamic"
|
||||
DESCRIPTION "Audio Output Virtual Channel Extension"
|
||||
SPECIFICATIONS "[MS-RDPEA]"
|
||||
DEFAULT ${OPTION_DEFAULT})
|
||||
|
|
|
@ -21,7 +21,7 @@ set(${MODULE_PREFIX}_SRCS
|
|||
rdpsnd_main.c
|
||||
rdpsnd_main.h)
|
||||
|
||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntryEx")
|
||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntryEx;DVCPluginEntry")
|
||||
|
||||
target_link_libraries(${MODULE_NAME}
|
||||
winpr freerdp ${CMAKE_THREAD_LIBS_INIT}
|
||||
|
|
|
@ -99,6 +99,7 @@ struct rdpsnd_plugin
|
|||
|
||||
BOOL attached;
|
||||
BOOL connected;
|
||||
BOOL dynamic;
|
||||
|
||||
BOOL expectingWave;
|
||||
BYTE waveData[4];
|
||||
|
@ -123,6 +124,13 @@ struct rdpsnd_plugin
|
|||
FREERDP_DSP_CONTEXT* dsp_context;
|
||||
};
|
||||
|
||||
static const char* rdpsnd_is_dyn_str(BOOL dynamic)
|
||||
{
|
||||
if (dynamic)
|
||||
return "[dynamic]";
|
||||
return "[static]";
|
||||
}
|
||||
|
||||
static void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd);
|
||||
|
||||
/**
|
||||
|
@ -144,7 +152,7 @@ static UINT rdpsnd_send_quality_mode_pdu(rdpsndPlugin* rdpsnd)
|
|||
|
||||
if (!pdu)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
WLog_ERR(TAG, "%s Stream_New failed!", rdpsnd_is_dyn_str(rdpsnd->dynamic));
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
|
@ -153,7 +161,8 @@ static UINT rdpsnd_send_quality_mode_pdu(rdpsndPlugin* rdpsnd)
|
|||
Stream_Write_UINT16(pdu, 4); /* BodySize */
|
||||
Stream_Write_UINT16(pdu, rdpsnd->wQualityMode); /* wQualityMode */
|
||||
Stream_Write_UINT16(pdu, 0); /* Reserved */
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG, "QualityMode: %" PRIu16 "", rdpsnd->wQualityMode);
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s QualityMode: %" PRIu16 "",
|
||||
rdpsnd_is_dyn_str(rdpsnd->dynamic), rdpsnd->wQualityMode);
|
||||
return rdpsnd_virtual_channel_write(rdpsnd, pdu);
|
||||
}
|
||||
|
||||
|
@ -211,7 +220,7 @@ static UINT rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd)
|
|||
|
||||
if (!pdu)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
WLog_ERR(TAG, "%s Stream_New failed!", rdpsnd_is_dyn_str(rdpsnd->dynamic));
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
|
@ -238,7 +247,8 @@ static UINT rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd)
|
|||
}
|
||||
}
|
||||
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Client Audio Formats");
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Client Audio Formats",
|
||||
rdpsnd_is_dyn_str(rdpsnd->dynamic));
|
||||
return rdpsnd_virtual_channel_write(rdpsnd, pdu);
|
||||
}
|
||||
|
||||
|
@ -288,7 +298,8 @@ static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream*
|
|||
}
|
||||
|
||||
rdpsnd_select_supported_audio_formats(rdpsnd);
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Server Audio Formats");
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Server Audio Formats",
|
||||
rdpsnd_is_dyn_str(rdpsnd->dynamic));
|
||||
ret = rdpsnd_send_client_audio_formats(rdpsnd);
|
||||
|
||||
if (ret == CHANNEL_RC_OK)
|
||||
|
@ -318,7 +329,7 @@ static UINT rdpsnd_send_training_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeS
|
|||
|
||||
if (!pdu)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
WLog_ERR(TAG, "%s Stream_New failed!", rdpsnd_is_dyn_str(rdpsnd->dynamic));
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
|
@ -328,8 +339,8 @@ static UINT rdpsnd_send_training_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeS
|
|||
Stream_Write_UINT16(pdu, wTimeStamp);
|
||||
Stream_Write_UINT16(pdu, wPackSize);
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG,
|
||||
"Training Response: wTimeStamp: %" PRIu16 " wPackSize: %" PRIu16 "", wTimeStamp,
|
||||
wPackSize);
|
||||
"%s Training Response: wTimeStamp: %" PRIu16 " wPackSize: %" PRIu16 "",
|
||||
rdpsnd_is_dyn_str(rdpsnd->dynamic), wTimeStamp, wPackSize);
|
||||
return rdpsnd_virtual_channel_write(rdpsnd, pdu);
|
||||
}
|
||||
|
||||
|
@ -349,8 +360,8 @@ static UINT rdpsnd_recv_training_pdu(rdpsndPlugin* rdpsnd, wStream* s)
|
|||
Stream_Read_UINT16(s, wTimeStamp);
|
||||
Stream_Read_UINT16(s, wPackSize);
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG,
|
||||
"Training Request: wTimeStamp: %" PRIu16 " wPackSize: %" PRIu16 "", wTimeStamp,
|
||||
wPackSize);
|
||||
"%s Training Request: wTimeStamp: %" PRIu16 " wPackSize: %" PRIu16 "",
|
||||
rdpsnd_is_dyn_str(rdpsnd->dynamic), wTimeStamp, wPackSize);
|
||||
return rdpsnd_send_training_confirm_pdu(rdpsnd, wTimeStamp, wPackSize);
|
||||
}
|
||||
|
||||
|
@ -380,7 +391,8 @@ static BOOL rdpsnd_ensure_device_is_open(rdpsndPlugin* rdpsnd, UINT32 wFormatNo,
|
|||
}
|
||||
}
|
||||
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Opening device with format %s [backend %s]",
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Opening device with format %s [backend %s]",
|
||||
rdpsnd_is_dyn_str(rdpsnd->dynamic),
|
||||
audio_format_get_tag_string(format->wFormatTag),
|
||||
audio_format_get_tag_string(deviceFormat.wFormatTag));
|
||||
rc = IFCALLRESULT(FALSE, rdpsnd->device->Open, rdpsnd->device, &deviceFormat,
|
||||
|
@ -430,8 +442,9 @@ static UINT rdpsnd_recv_wave_info_pdu(rdpsndPlugin* rdpsnd, wStream* s, UINT16 B
|
|||
rdpsnd->waveDataSize = BodySize - 8;
|
||||
format = &rdpsnd->ClientFormats[wFormatNo];
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG,
|
||||
"WaveInfo: cBlockNo: %" PRIu8 " wFormatNo: %" PRIu16 " [%s]", rdpsnd->cBlockNo,
|
||||
wFormatNo, audio_format_get_tag_string(format->wFormatTag));
|
||||
"%s WaveInfo: cBlockNo: %" PRIu8 " wFormatNo: %" PRIu16 " [%s]",
|
||||
rdpsnd_is_dyn_str(rdpsnd->dynamic), rdpsnd->cBlockNo, wFormatNo,
|
||||
audio_format_get_tag_string(format->wFormatTag));
|
||||
|
||||
if (!rdpsnd_ensure_device_is_open(rdpsnd, wFormatNo, format))
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
@ -453,7 +466,7 @@ static UINT rdpsnd_send_wave_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp
|
|||
|
||||
if (!pdu)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
WLog_ERR(TAG, "%s Stream_New failed!", rdpsnd_is_dyn_str(rdpsnd->dynamic));
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
|
@ -495,7 +508,8 @@ static BOOL rdpsnd_detect_overrun(rdpsndPlugin* rdpsnd, const AUDIO_FORMAT* form
|
|||
else if (now - rdpsnd->startPlayTime > totalDuration + 10)
|
||||
{
|
||||
/* Buffer underrun */
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Buffer underrun by %u ms",
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Buffer underrun by %u ms",
|
||||
rdpsnd_is_dyn_str(rdpsnd->dynamic),
|
||||
(UINT)(now - rdpsnd->startPlayTime - totalDuration));
|
||||
rdpsnd->startPlayTime = now;
|
||||
rdpsnd->totalPlaySize = size;
|
||||
|
@ -511,8 +525,8 @@ static BOOL rdpsnd_detect_overrun(rdpsndPlugin* rdpsnd, const AUDIO_FORMAT* form
|
|||
|
||||
if (remainingDuration + duration > maxDuration)
|
||||
{
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Buffer overrun pending %u ms dropping %u ms",
|
||||
remainingDuration, duration);
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Buffer overrun pending %u ms dropping %u ms",
|
||||
rdpsnd_is_dyn_str(rdpsnd->dynamic), remainingDuration, duration);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -535,8 +549,8 @@ static UINT rdpsnd_treat_wave(rdpsndPlugin* rdpsnd, wStream* s, size_t size)
|
|||
data = Stream_Pointer(s);
|
||||
format = &rdpsnd->ClientFormats[rdpsnd->wCurrentFormatNo];
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG,
|
||||
"Wave: cBlockNo: %" PRIu8 " wTimeStamp: %" PRIu16 ", size: %" PRIdz,
|
||||
rdpsnd->cBlockNo, rdpsnd->wTimeStamp, size);
|
||||
"%s Wave: cBlockNo: %" PRIu8 " wTimeStamp: %" PRIu16 ", size: %" PRIdz,
|
||||
rdpsnd_is_dyn_str(rdpsnd->dynamic), rdpsnd->cBlockNo, rdpsnd->wTimeStamp, size);
|
||||
|
||||
if (rdpsnd->device && rdpsnd->attached && !rdpsnd_detect_overrun(rdpsnd, format, size))
|
||||
{
|
||||
|
@ -564,8 +578,8 @@ static UINT rdpsnd_treat_wave(rdpsndPlugin* rdpsnd, wStream* s, size_t size)
|
|||
diffMS = end - rdpsnd->wArrivalTime + latency;
|
||||
ts = (rdpsnd->wTimeStamp + diffMS) % UINT16_MAX;
|
||||
|
||||
/* Don't send wave confirm PDU if not on static channel */
|
||||
if (rdpsnd->listener_callback)
|
||||
/* Don't send wave confirm PDU if on dynamic channel */
|
||||
if (rdpsnd->dynamic)
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
return rdpsnd_send_wave_confirm_pdu(rdpsnd, (UINT16)ts, rdpsnd->cBlockNo);
|
||||
|
@ -611,8 +625,9 @@ static UINT rdpsnd_recv_wave2_pdu(rdpsndPlugin* rdpsnd, wStream* s, UINT16 BodyS
|
|||
format = &rdpsnd->ClientFormats[wFormatNo];
|
||||
rdpsnd->wArrivalTime = GetTickCount64();
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG,
|
||||
"Wave2PDU: cBlockNo: %" PRIu8 " wFormatNo: %" PRIu16 ", align=%hu", rdpsnd->cBlockNo,
|
||||
wFormatNo, format->nBlockAlign);
|
||||
"%s Wave2PDU: cBlockNo: %" PRIu8 " wFormatNo: %" PRIu16 ", align=%hu",
|
||||
rdpsnd_is_dyn_str(rdpsnd->dynamic), rdpsnd->cBlockNo, wFormatNo,
|
||||
format->nBlockAlign);
|
||||
|
||||
if (!rdpsnd_ensure_device_is_open(rdpsnd, wFormatNo, format))
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
@ -624,10 +639,12 @@ static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd)
|
|||
{
|
||||
if (rdpsnd->isOpen)
|
||||
{
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Closing device");
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Closing device",
|
||||
rdpsnd_is_dyn_str(rdpsnd->dynamic));
|
||||
}
|
||||
else
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Device already closed");
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Device already closed",
|
||||
rdpsnd_is_dyn_str(rdpsnd->dynamic));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -644,12 +661,13 @@ static UINT rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s)
|
|||
return ERROR_BAD_LENGTH;
|
||||
|
||||
Stream_Read_UINT32(s, dwVolume);
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Volume: 0x%08" PRIX32 "", dwVolume);
|
||||
WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Volume: 0x%08" PRIX32 "",
|
||||
rdpsnd_is_dyn_str(rdpsnd->dynamic), dwVolume);
|
||||
rc = IFCALLRESULT(FALSE, rdpsnd->device->SetVolume, rdpsnd->device, dwVolume);
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
WLog_ERR(TAG, "error setting volume");
|
||||
WLog_ERR(TAG, "%s error setting volume", rdpsnd_is_dyn_str(rdpsnd->dynamic));
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR;
|
||||
}
|
||||
|
||||
|
@ -710,7 +728,8 @@ static UINT rdpsnd_recv_pdu(rdpsndPlugin* rdpsnd, wStream* s)
|
|||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "unknown msgType %" PRIu8 "", msgType);
|
||||
WLog_ERR(TAG, "%s unknown msgType %" PRIu8 "", rdpsnd_is_dyn_str(rdpsnd->dynamic),
|
||||
msgType);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -723,7 +742,7 @@ static void rdpsnd_register_device_plugin(rdpsndPlugin* rdpsnd, rdpsndDevicePlug
|
|||
{
|
||||
if (rdpsnd->device)
|
||||
{
|
||||
WLog_ERR(TAG, "existing device, abort.");
|
||||
WLog_ERR(TAG, "%s existing device, abort.", rdpsnd_is_dyn_str(FALSE));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -741,7 +760,11 @@ static UINT rdpsnd_load_device_plugin(rdpsndPlugin* rdpsnd, const char* name, AD
|
|||
PFREERDP_RDPSND_DEVICE_ENTRY entry;
|
||||
FREERDP_RDPSND_DEVICE_ENTRY_POINTS entryPoints;
|
||||
UINT error;
|
||||
entry = (PFREERDP_RDPSND_DEVICE_ENTRY)freerdp_load_channel_addin_entry("rdpsnd", name, NULL, 0);
|
||||
DWORD flags = FREERDP_ADDIN_CHANNEL_STATIC | FREERDP_ADDIN_CHANNEL_ENTRYEX;
|
||||
if (rdpsnd->dynamic)
|
||||
flags = FREERDP_ADDIN_CHANNEL_DYNAMIC;
|
||||
entry =
|
||||
(PFREERDP_RDPSND_DEVICE_ENTRY)freerdp_load_channel_addin_entry("rdpsnd", name, NULL, flags);
|
||||
|
||||
if (!entry)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
@ -751,9 +774,10 @@ static UINT rdpsnd_load_device_plugin(rdpsndPlugin* rdpsnd, const char* name, AD
|
|||
entryPoints.args = args;
|
||||
|
||||
if ((error = entry(&entryPoints)))
|
||||
WLog_ERR(TAG, "%s entry returns error %" PRIu32 "", name, error);
|
||||
WLog_ERR(TAG, "%s %s entry returns error %" PRIu32 "", rdpsnd_is_dyn_str(rdpsnd->dynamic),
|
||||
name, error);
|
||||
|
||||
WLog_INFO(TAG, "Loaded %s backend for rdpsnd", name);
|
||||
WLog_INFO(TAG, "%s Loaded %s backend for rdpsnd", rdpsnd_is_dyn_str(rdpsnd->dynamic), name);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -942,8 +966,9 @@ static UINT rdpsnd_process_connect(rdpsndPlugin* rdpsnd)
|
|||
{
|
||||
if ((status = rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args)))
|
||||
{
|
||||
WLog_ERR(TAG, "Unable to load sound playback subsystem %s because of error %" PRIu32 "",
|
||||
rdpsnd->subsystem, status);
|
||||
WLog_ERR(TAG,
|
||||
"%s Unable to load sound playback subsystem %s because of error %" PRIu32 "",
|
||||
rdpsnd_is_dyn_str(rdpsnd->dynamic), rdpsnd->subsystem, status);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
@ -958,8 +983,9 @@ static UINT rdpsnd_process_connect(rdpsndPlugin* rdpsnd)
|
|||
|
||||
if ((status = rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args)))
|
||||
WLog_ERR(TAG,
|
||||
"Unable to load sound playback subsystem %s because of error %" PRIu32 "",
|
||||
subsystem_name, status);
|
||||
"%s Unable to load sound playback subsystem %s because of error %" PRIu32
|
||||
"",
|
||||
rdpsnd_is_dyn_str(rdpsnd->dynamic), subsystem_name, status);
|
||||
|
||||
if (!rdpsnd->device)
|
||||
continue;
|
||||
|
@ -989,10 +1015,14 @@ UINT rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s)
|
|||
|
||||
if (rdpsnd)
|
||||
{
|
||||
if (rdpsnd->listener_callback)
|
||||
if (rdpsnd->dynamic)
|
||||
{
|
||||
IWTSVirtualChannel* channel = rdpsnd->listener_callback->channel_callback->channel;
|
||||
status = channel->Write(channel, (UINT32)Stream_Length(s), Stream_Buffer(s), NULL);
|
||||
IWTSVirtualChannel* channel;
|
||||
if (rdpsnd->listener_callback)
|
||||
{
|
||||
channel = rdpsnd->listener_callback->channel_callback->channel;
|
||||
status = channel->Write(channel, (UINT32)Stream_Length(s), Stream_Buffer(s), NULL);
|
||||
}
|
||||
Stream_Free(s, TRUE);
|
||||
}
|
||||
else
|
||||
|
@ -1004,8 +1034,8 @@ UINT rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s)
|
|||
if (status != CHANNEL_RC_OK)
|
||||
{
|
||||
Stream_Free(s, TRUE);
|
||||
WLog_ERR(TAG, "pVirtualChannelWriteEx failed with %s [%08" PRIX32 "]",
|
||||
WTSErrorToString(status), status);
|
||||
WLog_ERR(TAG, "%s pVirtualChannelWriteEx failed with %s [%08" PRIX32 "]",
|
||||
rdpsnd_is_dyn_str(FALSE), WTSErrorToString(status), status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1068,14 +1098,15 @@ static VOID VCAPITYPE rdpsnd_virtual_channel_open_event_ex(LPVOID lpUserParam, D
|
|||
case CHANNEL_EVENT_DATA_RECEIVED:
|
||||
if (!rdpsnd || (rdpsnd->OpenHandle != openHandle))
|
||||
{
|
||||
WLog_ERR(TAG, "error no match");
|
||||
WLog_ERR(TAG, "%s error no match", rdpsnd_is_dyn_str(rdpsnd->dynamic));
|
||||
return;
|
||||
}
|
||||
if ((error = rdpsnd_virtual_channel_event_data_received(rdpsnd, pData, dataLength,
|
||||
totalLength, dataFlags)))
|
||||
WLog_ERR(TAG,
|
||||
"rdpsnd_virtual_channel_event_data_received failed with error %" PRIu32 "",
|
||||
error);
|
||||
"%s rdpsnd_virtual_channel_event_data_received failed with error %" PRIu32
|
||||
"",
|
||||
rdpsnd_is_dyn_str(rdpsnd->dynamic), error);
|
||||
|
||||
break;
|
||||
|
||||
|
@ -1092,8 +1123,13 @@ static VOID VCAPITYPE rdpsnd_virtual_channel_open_event_ex(LPVOID lpUserParam, D
|
|||
}
|
||||
|
||||
if (error && rdpsnd && rdpsnd->rdpcontext)
|
||||
setChannelError(rdpsnd->rdpcontext, error,
|
||||
"rdpsnd_virtual_channel_open_event_ex reported an error");
|
||||
{
|
||||
char buffer[8192];
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"%s rdpsnd_virtual_channel_open_event_ex reported an error",
|
||||
rdpsnd_is_dyn_str(rdpsnd->dynamic));
|
||||
setChannelError(rdpsnd->rdpcontext, error, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1105,14 +1141,17 @@ static UINT rdpsnd_virtual_channel_event_connected(rdpsndPlugin* rdpsnd, LPVOID
|
|||
UINT32 dataLength)
|
||||
{
|
||||
UINT32 status;
|
||||
WINPR_UNUSED(pData);
|
||||
WINPR_UNUSED(dataLength);
|
||||
|
||||
status = rdpsnd->channelEntryPoints.pVirtualChannelOpenEx(
|
||||
rdpsnd->InitHandle, &rdpsnd->OpenHandle, rdpsnd->channelDef.name,
|
||||
rdpsnd_virtual_channel_open_event_ex);
|
||||
|
||||
if (status != CHANNEL_RC_OK)
|
||||
{
|
||||
WLog_ERR(TAG, "pVirtualChannelOpenEx failed with %s [%08" PRIX32 "]",
|
||||
WTSErrorToString(status), status);
|
||||
WLog_ERR(TAG, "%s pVirtualChannelOpenEx failed with %s [%08" PRIX32 "]",
|
||||
rdpsnd_is_dyn_str(rdpsnd->dynamic), WTSErrorToString(status), status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -1153,8 +1192,8 @@ static UINT rdpsnd_virtual_channel_event_disconnected(rdpsndPlugin* rdpsnd)
|
|||
|
||||
if (CHANNEL_RC_OK != error)
|
||||
{
|
||||
WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]",
|
||||
WTSErrorToString(error), error);
|
||||
WLog_ERR(TAG, "%s pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]",
|
||||
rdpsnd_is_dyn_str(rdpsnd->dynamic), WTSErrorToString(error), error);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -1201,7 +1240,7 @@ static VOID VCAPITYPE rdpsnd_virtual_channel_init_event_ex(LPVOID lpUserParam, L
|
|||
|
||||
if (!plugin || (plugin->InitHandle != pInitHandle))
|
||||
{
|
||||
WLog_ERR(TAG, "error no match");
|
||||
WLog_ERR(TAG, "%s error no match", rdpsnd_is_dyn_str(plugin->dynamic));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1211,19 +1250,11 @@ static VOID VCAPITYPE rdpsnd_virtual_channel_init_event_ex(LPVOID lpUserParam, L
|
|||
break;
|
||||
|
||||
case CHANNEL_EVENT_CONNECTED:
|
||||
if ((error = rdpsnd_virtual_channel_event_connected(plugin, pData, dataLength)))
|
||||
WLog_ERR(TAG,
|
||||
"rdpsnd_virtual_channel_event_connected failed with error %" PRIu32 "!",
|
||||
error);
|
||||
|
||||
error = rdpsnd_virtual_channel_event_connected(plugin, pData, dataLength);
|
||||
break;
|
||||
|
||||
case CHANNEL_EVENT_DISCONNECTED:
|
||||
if ((error = rdpsnd_virtual_channel_event_disconnected(plugin)))
|
||||
WLog_ERR(TAG,
|
||||
"rdpsnd_virtual_channel_event_disconnected failed with error %" PRIu32 "!",
|
||||
error);
|
||||
|
||||
error = rdpsnd_virtual_channel_event_disconnected(plugin);
|
||||
break;
|
||||
|
||||
case CHANNEL_EVENT_TERMINATED:
|
||||
|
@ -1243,8 +1274,12 @@ static VOID VCAPITYPE rdpsnd_virtual_channel_init_event_ex(LPVOID lpUserParam, L
|
|||
}
|
||||
|
||||
if (error && plugin && plugin->rdpcontext)
|
||||
setChannelError(plugin->rdpcontext, error,
|
||||
"rdpsnd_virtual_channel_init_event reported an error");
|
||||
{
|
||||
char buffer[8192];
|
||||
snprintf(buffer, sizeof(buffer), "%s %s reported an error",
|
||||
rdpsnd_is_dyn_str(plugin->dynamic), __FUNCTION__);
|
||||
setChannelError(plugin->rdpcontext, error, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
rdpContext* freerdp_rdpsnd_get_context(rdpsndPlugin* plugin)
|
||||
|
@ -1256,9 +1291,7 @@ rdpContext* freerdp_rdpsnd_get_context(rdpsndPlugin* plugin)
|
|||
}
|
||||
|
||||
/* rdpsnd is always built-in */
|
||||
#define VirtualChannelEntryEx rdpsnd_VirtualChannelEntryEx
|
||||
|
||||
BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID pInitHandle)
|
||||
BOOL VCAPITYPE rdpsnd_VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID pInitHandle)
|
||||
{
|
||||
UINT rc;
|
||||
rdpsndPlugin* rdpsnd;
|
||||
|
@ -1301,8 +1334,8 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p
|
|||
|
||||
if (CHANNEL_RC_OK != rc)
|
||||
{
|
||||
WLog_ERR(TAG, "pVirtualChannelInitEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
|
||||
rc);
|
||||
WLog_ERR(TAG, "%s pVirtualChannelInitEx failed with %s [%08" PRIX32 "]",
|
||||
rdpsnd_is_dyn_str(FALSE), WTSErrorToString(rc), rc);
|
||||
free(rdpsnd);
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -1371,9 +1404,12 @@ static UINT rdpsnd_on_new_channel_connection(IWTSListenerCallback* pListenerCall
|
|||
RDPSND_LISTENER_CALLBACK* listener_callback = (RDPSND_LISTENER_CALLBACK*)pListenerCallback;
|
||||
callback = (RDPSND_CHANNEL_CALLBACK*)calloc(1, sizeof(RDPSND_CHANNEL_CALLBACK));
|
||||
|
||||
WINPR_UNUSED(Data);
|
||||
WINPR_UNUSED(pbAccept);
|
||||
|
||||
if (!callback)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
WLog_ERR(TAG, "%s calloc failed!", rdpsnd_is_dyn_str(TRUE));
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
|
@ -1397,7 +1433,7 @@ static UINT rdpsnd_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelMana
|
|||
|
||||
if (!rdpsnd->listener_callback)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
WLog_ERR(TAG, "%s calloc failed!", rdpsnd_is_dyn_str(TRUE));
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
|
@ -1425,28 +1461,22 @@ static UINT rdpsnd_plugin_terminated(IWTSPlugin* pPlugin)
|
|||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
#ifdef BUILTIN_CHANNELS
|
||||
#define DVCPluginEntry rdpsnd_dyn_DVCPluginEntry
|
||||
#else
|
||||
#define DVCPluginEntry FREERDP_API DVCPluginEntry
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
UINT rdpsnd_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
{
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
rdpsndPlugin* rdpsnd = (rdpsndPlugin*)pEntryPoints->GetPlugin(pEntryPoints, "rdpsnd_dyn");
|
||||
rdpsndPlugin* rdpsnd = (rdpsndPlugin*)pEntryPoints->GetPlugin(pEntryPoints, "rdpsnd");
|
||||
|
||||
if (!rdpsnd)
|
||||
{
|
||||
rdpsnd = (rdpsndPlugin*)calloc(1, sizeof(rdpsndPlugin));
|
||||
if (!rdpsnd)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
WLog_ERR(TAG, "%s calloc failed!", rdpsnd_is_dyn_str(TRUE));
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
|
@ -1455,6 +1485,7 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
|||
rdpsnd->iface.Disconnected = NULL;
|
||||
rdpsnd->iface.Terminated = rdpsnd_plugin_terminated;
|
||||
rdpsnd->attached = TRUE;
|
||||
rdpsnd->dynamic = TRUE;
|
||||
rdpsnd->fixed_format = audio_format_new();
|
||||
if (!rdpsnd->fixed_format)
|
||||
{
|
||||
|
@ -1464,11 +1495,11 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
|||
rdpsnd->log = WLog_Get("com.freerdp.channels.rdpsnd.client");
|
||||
rdpsnd->channelEntryPoints.pExtendedData = pEntryPoints->GetPluginData(pEntryPoints);
|
||||
|
||||
error = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpsnd_dyn", (IWTSPlugin*)rdpsnd);
|
||||
error = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpsnd", &rdpsnd->iface);
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_ERR(TAG, "could not get disp Plugin.");
|
||||
WLog_ERR(TAG, "%s could not get disp Plugin.", rdpsnd_is_dyn_str(TRUE));
|
||||
return CHANNEL_RC_BAD_CHANNEL;
|
||||
}
|
||||
|
||||
|
|
|
@ -926,7 +926,6 @@ static int freerdp_client_command_line_post_filter(void* context, COMMAND_LINE_A
|
|||
status = freerdp_client_add_static_channel(settings, count, p);
|
||||
if (status)
|
||||
{
|
||||
p[0] = "rdpsnd_dyn";
|
||||
status = freerdp_client_add_dynamic_channel(settings, count, p);
|
||||
}
|
||||
free(p);
|
||||
|
@ -3272,7 +3271,7 @@ BOOL freerdp_client_load_addins(rdpChannels* channels, rdpSettings* settings)
|
|||
/* for audio playback also load the dynamic sound channel */
|
||||
if (settings->AudioPlayback)
|
||||
{
|
||||
char* p[] = { "rdpsnd_dyn" };
|
||||
char* p[] = { "rdpsnd" };
|
||||
|
||||
if (!freerdp_client_add_dynamic_channel(settings, ARRAYSIZE(p), p))
|
||||
return FALSE;
|
||||
|
@ -3287,7 +3286,7 @@ BOOL freerdp_client_load_addins(rdpChannels* channels, rdpSettings* settings)
|
|||
}
|
||||
|
||||
if ((freerdp_static_channel_collection_find(settings, "rdpsnd")) ||
|
||||
(freerdp_dynamic_channel_collection_find(settings, "rdpsnd_dyn"))
|
||||
(freerdp_dynamic_channel_collection_find(settings, "rdpsnd"))
|
||||
#if defined(CHANNEL_TSMF_CLIENT)
|
||||
|| (freerdp_dynamic_channel_collection_find(settings, "tsmf"))
|
||||
#endif
|
||||
|
@ -3413,7 +3412,7 @@ BOOL freerdp_client_load_addins(rdpChannels* channels, rdpSettings* settings)
|
|||
return FALSE;
|
||||
|
||||
if (!freerdp_static_channel_collection_find(settings, "rdpsnd") &&
|
||||
!freerdp_dynamic_channel_collection_find(settings, "rdpsnd_dyn"))
|
||||
!freerdp_dynamic_channel_collection_find(settings, "rdpsnd"))
|
||||
{
|
||||
char* params[2];
|
||||
params[0] = "rdpsnd";
|
||||
|
|
Загрузка…
Ссылка в новой задаче