From 5bc908def1cbcfbad79ef191d3649236eaf28fce Mon Sep 17 00:00:00 2001 From: Bernhard Miklautz Date: Wed, 21 Nov 2018 15:18:12 +0100 Subject: [PATCH] New upstream version 2.0.0~git20181120.1.e21b72c95+dfsg1 --- .source_version | 1 + CMakeLists.txt | 213 +- ChangeLog | 3071 +++++++++++++++++ README | 2 +- channels/audin/client/alsa/audin_alsa.c | 359 +- channels/audin/client/audin_main.c | 387 ++- channels/audin/client/audin_main.h | 6 - channels/audin/client/mac/audin_mac.c | 579 ++-- .../audin/client/opensles/audin_opensl_es.c | 346 +- channels/audin/client/opensles/opensl_io.c | 224 +- channels/audin/client/opensles/opensl_io.h | 41 +- channels/audin/client/oss/audin_oss.c | 107 +- channels/audin/client/pulse/audin_pulse.c | 232 +- channels/audin/client/winmm/audin_winmm.c | 196 +- channels/audin/server/audin.c | 151 +- channels/client/addin.c | 13 +- channels/cliprdr/client/cliprdr_main.c | 15 +- channels/drdynvc/client/drdynvc_main.c | 73 +- channels/drive/client/drive_file.c | 64 +- channels/drive/client/drive_main.c | 65 +- channels/encomsp/client/encomsp_main.c | 8 +- channels/printer/client/printer_main.c | 26 +- channels/rail/client/rail_main.c | 142 +- channels/rail/client/rail_orders.c | 135 +- channels/rail/client/rail_orders.h | 29 +- channels/rail/rail_common.c | 20 +- channels/rail/rail_common.h | 6 +- channels/rdpdr/client/devman.c | 7 +- channels/rdpdr/client/rdpdr_main.c | 68 +- channels/rdpdr/server/rdpdr_main.c | 29 +- channels/rdpgfx/client/rdpgfx_codec.c | 6 +- channels/rdpsnd/CMakeLists.txt | 3 + channels/rdpsnd/client/CMakeLists.txt | 9 +- channels/rdpsnd/client/alsa/rdpsnd_alsa.c | 366 +- channels/rdpsnd/client/fake/CMakeLists.txt | 33 + channels/rdpsnd/client/fake/rdpsnd_fake.c | 172 + channels/rdpsnd/client/ios/rdpsnd_ios.c | 85 +- channels/rdpsnd/client/mac/rdpsnd_mac.c | 274 +- .../rdpsnd/client/opensles/rdpsnd_opensles.c | 89 +- channels/rdpsnd/client/oss/rdpsnd_oss.c | 106 +- channels/rdpsnd/client/pulse/CMakeLists.txt | 6 - channels/rdpsnd/client/pulse/rdpsnd_pulse.c | 329 +- channels/rdpsnd/client/rdpsnd_main.c | 930 ++--- channels/rdpsnd/client/rdpsnd_main.h | 2 - channels/rdpsnd/client/winmm/rdpsnd_winmm.c | 186 +- channels/rdpsnd/common/CMakeLists.txt | 24 + channels/rdpsnd/common/rdpsnd_common.h | 43 + channels/rdpsnd/server/CMakeLists.txt | 5 - channels/rdpsnd/server/rdpsnd_main.c | 295 +- channels/remdesk/client/remdesk_main.c | 11 +- channels/remdesk/server/remdesk_main.c | 7 +- channels/serial/client/serial_main.c | 3 + channels/server/channels.c | 61 +- channels/smartcard/client/smartcard_main.c | 279 +- channels/smartcard/client/smartcard_main.h | 9 +- .../smartcard/client/smartcard_operations.c | 89 +- channels/sshagent/server/sshagent_main.c | 6 +- channels/tsmf/client/alsa/tsmf_alsa.c | 139 +- channels/tsmf/client/oss/tsmf_oss.c | 16 +- channels/tsmf/client/pulse/tsmf_pulse.c | 229 +- channels/tsmf/client/tsmf_audio.h | 17 +- channels/tsmf/client/tsmf_main.c | 114 +- channels/tsmf/client/tsmf_media.c | 33 +- .../urbdrc/client/libusb/libusb_udevice.c | 9 +- .../urbdrc/client/libusb/libusb_udevman.c | 4 +- channels/urbdrc/client/urbdrc_main.c | 20 +- channels/video/client/video_main.c | 1 + client/CMakeLists.txt | 2 +- client/DirectFB/dfreerdp.c | 1 - client/Wayland/wlf_channels.c | 21 +- client/Wayland/wlf_input.c | 58 +- client/Wayland/wlfreerdp.c | 64 +- client/X11/CMakeLists.txt | 2 + client/X11/generate_argument_docbook.c | 110 +- client/X11/resource/close.xbm | 11 + client/X11/resource/lock.xbm | 11 + client/X11/resource/minimize.xbm | 11 + client/X11/resource/restore.xbm | 11 + client/X11/resource/unlock.xbm | 11 + client/X11/xf_channels.c | 6 +- client/X11/xf_channels.h | 3 - client/X11/xf_client.c | 170 +- client/X11/xf_cliprdr.c | 19 +- client/X11/xf_disp.c | 383 +- client/X11/xf_disp.h | 13 +- client/X11/xf_event.c | 27 +- client/X11/xf_floatbar.c | 722 ++++ client/X11/xf_floatbar.h | 34 + client/X11/xf_gdi.c | 18 +- client/X11/xf_graphics.c | 14 +- client/X11/xf_keyboard.c | 32 +- client/X11/xf_monitor.c | 99 +- client/X11/xf_rail.c | 369 +- client/X11/xf_window.c | 108 +- client/X11/xf_window.h | 15 +- client/X11/xfreerdp.h | 6 +- client/common/client.c | 75 +- client/common/cmdline.c | 648 ++-- client/common/cmdline.h | 42 +- client/common/compatibility.c | 10 +- client/common/file.c | 3 +- client/common/test/TestClientCmdLine.c | 373 +- cmake/AndroidToolchain.cmake | 4 + cmake/ConfigOptions.cmake | 5 + cmake/FindFAAC.cmake | 13 + cmake/FindFAAD2.cmake | 13 + cmake/FindFFmpeg.cmake | 55 +- cmake/FindLAME.cmake | 13 + cmake/FindUUID.cmake | 3 - cmake/Findlibusb-1.0.cmake | 2 - cmake/Findsoxr.cmake | 62 + cmake/InstallFreeRDPMan.cmake | 2 +- cmake/SetFreeRDPCMakeInstallDir.cmake | 7 + config.h.in | 8 + docs/README.timezones | 12 + include/freerdp/api.h | 2 +- include/freerdp/channels/rdpdr.h | 2 +- include/freerdp/client.h | 36 +- include/freerdp/client/audin.h | 26 +- include/freerdp/client/rail.h | 59 +- include/freerdp/client/rdpsnd.h | 50 +- include/freerdp/codec/audio.h | 26 +- include/freerdp/codec/bitmap.h | 4 +- include/freerdp/codec/dsp.h | 63 +- include/freerdp/codec/nsc.h | 4 +- include/freerdp/codec/zgfx.h | 30 +- include/freerdp/crypto/crypto.h | 47 +- include/freerdp/crypto/tls.h | 16 +- include/freerdp/error.h | 4 + include/freerdp/freerdp.h | 25 +- include/freerdp/gdi/bitmap.h | 12 +- include/freerdp/gdi/gdi.h | 42 +- include/freerdp/gdi/region.h | 54 +- include/freerdp/gdi/shape.h | 4 +- include/freerdp/graphics.h | 17 +- include/freerdp/peer.h | 6 +- include/freerdp/pointer.h | 8 - include/freerdp/primary.h | 2 +- include/freerdp/rail.h | 3 - include/freerdp/secondary.h | 25 +- include/freerdp/server/audin.h | 24 +- include/freerdp/server/rdpsnd.h | 37 +- include/freerdp/server/server-common.h | 31 + include/freerdp/server/shadow.h | 117 +- include/freerdp/settings.h | 1362 ++++---- include/freerdp/update.h | 7 - include/freerdp/utils/profiler.h | 11 +- libfreerdp/CMakeLists.txt | 35 +- libfreerdp/cache/CMakeLists.txt | 8 +- libfreerdp/cache/bitmap.c | 245 +- libfreerdp/cache/bitmap.h | 41 + libfreerdp/cache/brush.c | 48 +- libfreerdp/cache/brush.h | 31 + libfreerdp/cache/cache.c | 52 + libfreerdp/cache/cache.h | 36 + libfreerdp/cache/glyph.c | 122 + libfreerdp/cache/glyph.h | 35 + libfreerdp/cache/palette.c | 34 +- libfreerdp/cache/palette.h | 30 + libfreerdp/cache/pointer.c | 180 +- libfreerdp/cache/pointer.h | 49 + libfreerdp/codec/audio.c | 189 +- libfreerdp/codec/bitmap.c | 2065 +++++------ libfreerdp/codec/clear.c | 30 +- libfreerdp/codec/color.c | 61 +- libfreerdp/codec/dsp.c | 926 ++++- libfreerdp/codec/dsp.h | 34 + libfreerdp/codec/dsp_ffmpeg.c | 678 ++++ libfreerdp/codec/dsp_ffmpeg.h | 48 + libfreerdp/codec/h264.c | 22 +- libfreerdp/codec/include/bitmap.c | 437 +-- libfreerdp/codec/interleaved.c | 156 +- libfreerdp/codec/nsc.c | 142 +- libfreerdp/codec/nsc_encode.c | 62 +- libfreerdp/codec/nsc_encode.h | 2 +- libfreerdp/codec/nsc_sse2.c | 6 +- libfreerdp/codec/planar.c | 290 +- libfreerdp/codec/rfx.c | 29 +- libfreerdp/codec/rfx_bitstream.h | 7 + libfreerdp/codec/rfx_neon.c | 129 +- libfreerdp/codec/rfx_rlgr.c | 1 + libfreerdp/codec/rfx_sse2.c | 8 +- libfreerdp/codec/test/CMakeLists.txt | 1 + libfreerdp/codec/test/TestFreeRDPCodecClear.c | 47 +- .../codec/test/TestFreeRDPCodecInterleaved.c | 179 + .../codec/test/TestFreeRDPCodecPlanar.c | 73 +- libfreerdp/codec/zgfx.c | 95 +- libfreerdp/common/addin.c | 8 +- libfreerdp/common/settings.c | 151 +- libfreerdp/core/activation.c | 71 +- libfreerdp/core/autodetect.c | 331 +- libfreerdp/core/capabilities.c | 26 +- libfreerdp/core/certificate.c | 2 +- libfreerdp/core/channels.c | 5 +- libfreerdp/core/channels.h | 2 +- libfreerdp/core/client.c | 96 +- libfreerdp/core/connection.c | 327 +- libfreerdp/core/connection.h | 9 +- libfreerdp/core/errconnect.c | 4 + libfreerdp/core/errinfo.c | 2 +- libfreerdp/core/fastpath.c | 193 +- libfreerdp/core/freerdp.c | 178 +- libfreerdp/core/gateway/http.c | 472 ++- libfreerdp/core/gateway/http.h | 84 +- libfreerdp/core/gateway/ncacn_http.c | 176 +- libfreerdp/core/gateway/ncacn_http.h | 26 +- libfreerdp/core/gateway/ntlm.c | 137 +- libfreerdp/core/gateway/ntlm.h | 68 +- libfreerdp/core/gateway/rdg.c | 1257 +++---- libfreerdp/core/gateway/rdg.h | 112 +- libfreerdp/core/gateway/rpc.c | 344 +- libfreerdp/core/gateway/rpc.h | 62 +- libfreerdp/core/gateway/rpc_bind.c | 148 +- libfreerdp/core/gateway/rpc_bind.h | 6 +- libfreerdp/core/gateway/rpc_client.c | 295 +- libfreerdp/core/gateway/rpc_client.h | 13 +- libfreerdp/core/gateway/rts.c | 92 +- libfreerdp/core/gateway/rts.h | 3 +- libfreerdp/core/gateway/rts_signature.c | 147 +- libfreerdp/core/gateway/rts_signature.h | 117 +- libfreerdp/core/gateway/tsg.c | 1694 +++++---- libfreerdp/core/gateway/tsg.h | 209 +- libfreerdp/core/gcc.c | 47 +- libfreerdp/core/info.c | 120 +- libfreerdp/core/info.h | 2 + libfreerdp/core/license.c | 685 +++- libfreerdp/core/license.h | 2 +- libfreerdp/core/listener.c | 25 +- libfreerdp/core/mcs.h | 9 - libfreerdp/core/message.c | 648 ++-- libfreerdp/core/nego.c | 101 +- libfreerdp/core/nego.h | 17 +- libfreerdp/core/nla.c | 163 +- libfreerdp/core/orders.c | 1554 +++++---- libfreerdp/core/peer.c | 9 +- libfreerdp/core/proxy.c | 413 ++- libfreerdp/core/proxy.h | 5 +- libfreerdp/core/rdp.c | 383 +- libfreerdp/core/rdp.h | 6 +- libfreerdp/core/redirection.c | 6 +- libfreerdp/core/server.c | 4 +- libfreerdp/core/settings.c | 57 +- libfreerdp/core/surface.c | 44 +- libfreerdp/core/tcp.c | 164 +- libfreerdp/core/tcp.h | 6 + libfreerdp/core/transport.c | 184 +- libfreerdp/core/transport.h | 5 +- libfreerdp/core/update.c | 424 ++- libfreerdp/core/update.h | 24 +- libfreerdp/core/window.c | 196 +- libfreerdp/crypto/certificate.c | 33 +- libfreerdp/crypto/crypto.c | 580 +++- libfreerdp/crypto/test/CMakeLists.txt | 5 +- libfreerdp/crypto/test/TestKnownHosts.c | 6 +- libfreerdp/crypto/test/Test_x509_cert_info.c | 175 + .../crypto/test/Test_x509_cert_info.pem | 41 + libfreerdp/crypto/tls.c | 407 ++- libfreerdp/gdi/bitmap.c | 169 +- libfreerdp/gdi/clipping.c | 8 +- libfreerdp/gdi/clipping.h | 8 +- libfreerdp/gdi/drawing.c | 10 +- libfreerdp/gdi/drawing.h | 6 +- libfreerdp/gdi/gdi.c | 56 +- libfreerdp/gdi/gdi.h | 4 +- libfreerdp/gdi/gfx.c | 12 +- libfreerdp/gdi/graphics.c | 113 +- libfreerdp/gdi/line.c | 2 +- libfreerdp/gdi/region.c | 55 +- libfreerdp/gdi/shape.c | 12 +- libfreerdp/gdi/test/TestGdiBitBlt.c | 13 - libfreerdp/gdi/test/TestGdiLine.c | 42 - libfreerdp/locale/keyboard_layout.c | 77 +- libfreerdp/locale/keyboard_xkbfile.c | 2 +- libfreerdp/locale/locale.c | 25 +- libfreerdp/primitives/primitives.c | 8 +- .../primitives/test/TestPrimitivesAlphaComp.c | 55 +- .../primitives/test/TestPrimitivesSet.c | 65 +- libfreerdp/primitives/test/measure.h | 2 +- libfreerdp/utils/profiler.c | 33 +- libfreerdp/utils/signal.c | 2 +- packaging/deb/freerdp-nightly/control | 3 +- packaging/deb/freerdp-nightly/rules | 4 +- packaging/rpm/freerdp-nightly.spec | 13 +- rdtk/librdtk/rdtk_font.c | 9 +- rdtk/librdtk/rdtk_nine_patch.c | 4 + scripts/TimeZones.csx | 18 +- scripts/WindowsZones.csx | 9 +- scripts/android-build-32.conf | 2 +- scripts/android-build-64.conf | 2 +- scripts/android-build.conf | 2 +- scripts/update-rdpSettings | 51 + server/CMakeLists.txt | 2 +- server/Mac/mf_audin.c | 22 +- server/Mac/mf_peer.c | 26 +- server/Mac/mf_rdpsnd.c | 19 +- server/Sample/sf_audin.c | 24 +- server/Sample/sf_rdpsnd.c | 18 +- server/Sample/sfreerdp.c | 98 +- server/Windows/wf_rdpsnd.c | 62 +- server/common/server.c | 152 + server/shadow/CMakeLists.txt | 2 +- server/shadow/Mac/mac_shadow.c | 88 +- server/shadow/Mac/mac_shadow.h | 2 +- server/shadow/Win/win_rdp.c | 1 - server/shadow/X11/x11_shadow.c | 179 +- server/shadow/X11/x11_shadow.h | 2 +- server/shadow/shadow_audin.c | 69 +- server/shadow/shadow_audin.h | 2 +- server/shadow/shadow_capture.c | 29 +- server/shadow/shadow_client.c | 86 +- server/shadow/shadow_input.c | 60 +- server/shadow/shadow_rdpsnd.c | 37 +- server/shadow/shadow_server.c | 2 +- uwac/CMakeLists.txt | 2 +- uwac/include/uwac/uwac.h | 17 +- uwac/libuwac/CMakeLists.txt | 5 +- uwac/libuwac/uwac-display.c | 2 +- uwac/libuwac/uwac-input.c | 4 + uwac/libuwac/uwac-os.c | 92 +- uwac/libuwac/uwac-window.c | 12 +- winpr/CMakeLists.txt | 10 +- winpr/include/winpr/cmdline.h | 8 +- winpr/include/winpr/collections.h | 157 +- winpr/include/winpr/endian.h | 106 +- winpr/include/winpr/ntlm.h | 27 +- winpr/include/winpr/stream.h | 18 +- winpr/include/winpr/strlst.h | 41 + winpr/include/winpr/winpr.h | 4 + winpr/libwinpr/CMakeLists.txt | 12 + winpr/libwinpr/clipboard/clipboard.c | 1 + winpr/libwinpr/clipboard/posix.c | 1 + winpr/libwinpr/clipboard/synthetic.c | 14 +- winpr/libwinpr/comm/comm.c | 20 +- winpr/libwinpr/comm/comm.h | 2 +- winpr/libwinpr/crt/alignment.c | 37 +- winpr/libwinpr/crt/utf.c | 862 ----- winpr/libwinpr/crt/utf.h | 152 - winpr/libwinpr/crypto/hash.c | 6 +- winpr/libwinpr/file/generic.c | 218 +- winpr/libwinpr/file/namedPipeClient.c | 75 +- winpr/libwinpr/handle/nonehandle.c | 28 +- winpr/libwinpr/io/device.c | 44 +- winpr/libwinpr/library/library.c | 8 +- winpr/libwinpr/path/shell.c | 38 +- winpr/libwinpr/path/shell_ios.h | 2 + winpr/libwinpr/path/shell_ios.m | 25 +- winpr/libwinpr/path/test/TestPathMakePath.c | 19 +- winpr/libwinpr/pipe/pipe.c | 16 +- winpr/libwinpr/shell/shell.c | 7 +- winpr/libwinpr/smartcard/smartcard_pcsc.c | 2 +- winpr/libwinpr/sspi/Kerberos/kerberos.c | 4 +- winpr/libwinpr/sspi/NTLM/ntlm.c | 10 +- winpr/libwinpr/sspi/NTLM/ntlm.h | 4 +- winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c | 314 +- winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h | 32 +- winpr/libwinpr/sspi/NTLM/ntlm_compute.c | 30 +- winpr/libwinpr/sspi/NTLM/ntlm_compute.h | 3 +- winpr/libwinpr/sspi/NTLM/ntlm_message.c | 212 +- winpr/libwinpr/sspi/Negotiate/negotiate.c | 4 +- .../libwinpr/sspi/Schannel/schannel_openssl.c | 9 +- winpr/libwinpr/sspi/sspi.h | 2 +- winpr/libwinpr/sspi/sspi_export.c | 5 +- winpr/libwinpr/sspi/sspi_winpr.c | 15 +- winpr/libwinpr/sspicli/sspicli.c | 54 +- winpr/libwinpr/synch/CMakeLists.txt | 5 +- winpr/libwinpr/synch/event.c | 18 +- winpr/libwinpr/synch/mutex.c | 44 +- winpr/libwinpr/synch/semaphore.c | 52 +- winpr/libwinpr/synch/synch.h | 4 - winpr/libwinpr/synch/test/CMakeLists.txt | 4 + winpr/libwinpr/synch/timer.c | 41 +- winpr/libwinpr/synch/wait.c | 82 +- winpr/libwinpr/thread/argv.c | 1 + winpr/libwinpr/thread/process.c | 147 +- winpr/libwinpr/thread/thread.c | 35 +- winpr/libwinpr/timezone/TimeZones.c | 1584 +++++++++ winpr/libwinpr/timezone/WindowsZones.c | 409 +++ winpr/libwinpr/timezone/timezone.c | 2093 +---------- winpr/libwinpr/utils/CMakeLists.txt | 8 +- winpr/libwinpr/utils/cmdline.c | 15 +- winpr/libwinpr/utils/collections/ArrayList.c | 65 +- winpr/libwinpr/utils/collections/LinkedList.c | 169 +- .../utils/collections/ListDictionary.c | 31 +- winpr/libwinpr/utils/collections/ObjectPool.c | 2 +- winpr/libwinpr/utils/collections/Queue.c | 22 +- winpr/libwinpr/utils/collections/Stack.c | 15 +- winpr/libwinpr/utils/collections/StreamPool.c | 1 + winpr/libwinpr/utils/lodepng/lodepng.c | 22 +- winpr/libwinpr/utils/ntlm.c | 128 +- winpr/libwinpr/utils/sam.c | 2 +- winpr/libwinpr/utils/ssl.c | 6 +- winpr/libwinpr/utils/stream.c | 36 +- winpr/libwinpr/utils/strlst.c | 83 + winpr/libwinpr/utils/test/TestCmdLine.c | 52 +- winpr/libwinpr/utils/test/TestImage.c | 4 +- winpr/libwinpr/utils/test/TestStream.c | 279 +- winpr/libwinpr/utils/trio/triodef.h | 2 +- winpr/libwinpr/utils/wlog/UdpAppender.c | 59 +- winpr/libwinpr/utils/wlog/wlog.c | 21 +- winpr/libwinpr/winsock/winsock.c | 223 +- winpr/tools/makecert/makecert.c | 38 +- 401 files changed, 28341 insertions(+), 18693 deletions(-) create mode 100644 .source_version create mode 100644 channels/rdpsnd/client/fake/CMakeLists.txt create mode 100644 channels/rdpsnd/client/fake/rdpsnd_fake.c create mode 100644 channels/rdpsnd/common/CMakeLists.txt create mode 100644 channels/rdpsnd/common/rdpsnd_common.h create mode 100644 client/X11/resource/close.xbm create mode 100644 client/X11/resource/lock.xbm create mode 100644 client/X11/resource/minimize.xbm create mode 100644 client/X11/resource/restore.xbm create mode 100644 client/X11/resource/unlock.xbm create mode 100644 client/X11/xf_floatbar.c create mode 100644 client/X11/xf_floatbar.h mode change 100644 => 100755 client/common/file.c create mode 100644 cmake/FindFAAC.cmake create mode 100644 cmake/FindFAAD2.cmake create mode 100644 cmake/FindLAME.cmake create mode 100644 cmake/Findsoxr.cmake create mode 100644 cmake/SetFreeRDPCMakeInstallDir.cmake create mode 100644 docs/README.timezones create mode 100644 include/freerdp/server/server-common.h create mode 100644 libfreerdp/cache/bitmap.h create mode 100644 libfreerdp/cache/brush.h create mode 100644 libfreerdp/cache/cache.h create mode 100644 libfreerdp/cache/glyph.h create mode 100644 libfreerdp/cache/palette.h create mode 100644 libfreerdp/cache/pointer.h create mode 100644 libfreerdp/codec/dsp.h create mode 100644 libfreerdp/codec/dsp_ffmpeg.c create mode 100644 libfreerdp/codec/dsp_ffmpeg.h create mode 100644 libfreerdp/codec/test/TestFreeRDPCodecInterleaved.c mode change 100644 => 100755 libfreerdp/core/gateway/rdg.h create mode 100644 libfreerdp/crypto/test/Test_x509_cert_info.c create mode 100644 libfreerdp/crypto/test/Test_x509_cert_info.pem create mode 100755 scripts/update-rdpSettings create mode 100644 winpr/include/winpr/strlst.h delete mode 100644 winpr/libwinpr/crt/utf.c delete mode 100644 winpr/libwinpr/crt/utf.h create mode 100644 winpr/libwinpr/timezone/TimeZones.c create mode 100644 winpr/libwinpr/timezone/WindowsZones.c create mode 100644 winpr/libwinpr/utils/strlst.c diff --git a/.source_version b/.source_version new file mode 100644 index 0000000..b196adb --- /dev/null +++ b/.source_version @@ -0,0 +1 @@ +e21b72c95+debian diff --git a/CMakeLists.txt b/CMakeLists.txt index 16368ac..0199269 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,6 +68,7 @@ include(GNUInstallDirsWrapper) include(CMakePackageConfigHelpers) include(InstallFreeRDPMan) include(GetGitRevisionDescription) +include(SetFreeRDPCMakeInstallDir) # Soname versioning set(BUILD_NUMBER 0) @@ -76,7 +77,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSTION_STRING "2.0.0-rc2") +set(RAW_VERSTION_STRING "2.0.0-rc4") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSTION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) @@ -198,6 +199,16 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "BSD") endif() endif() +if(${CMAKE_SYSTEM_NAME} MATCHES "DragonFly") + set(BSD TRUE) + set(FREEBSD TRUE) +endif() + +if(FREEBSD) + find_path(EPOLLSHIM_INCLUDE_DIR NAMES sys/epoll.h sys/timerfd.h HINTS /usr/local/include/libepoll-shim) + find_library(EPOLLSHIM_LIBS NAMES epoll-shim libepoll-shim HINTS /usr/local/lib) +endif() + # Configure MSVC Runtime if(MSVC) include(MSVCRuntime) @@ -219,8 +230,8 @@ if(MSVC) endif() endif() -# Enable 64bit file support on linux. -if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") +# Enable 64bit file support on linux and FreeBSD. +if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux" OR FREEBSD) add_definitions("-D_FILE_OFFSET_BITS=64") endif() @@ -328,102 +339,104 @@ endif() # Enable address sanitizer, where supported and when required if(${CMAKE_C_COMPILER_ID} STREQUAL "Clang" OR CMAKE_COMPILER_IS_GNUCC) + set(CMAKE_REQUIRED_FLAGS_SAVED ${CMAKE_REQUIRED_FLAGS}) + + CHECK_C_COMPILER_FLAG ("-fno-omit-frame-pointer" fno-omit-frame-pointer) + + file(WRITE ${CMAKE_BINARY_DIR}/foo.txt "") if(WITH_SANITIZE_ADDRESS) - if (DEFINED CMAKE_REQUIRED_FLAGS) - set(SAVE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) - endif() set(CMAKE_REQUIRED_FLAGS "-fsanitize=address") CHECK_C_COMPILER_FLAG ("-fsanitize=address" fsanitize-address) + CHECK_C_COMPILER_FLAG ("-fsanitize-blacklist=${CMAKE_BINARY_DIR}/foo.txt" fsanitize-blacklist) + CHECK_C_COMPILER_FLAG ("-fsanitize-address-use-after-scope" fsanitize-address-use-after-scope) + unset(CMAKE_REQUIRED_FLAGS) + if(fsanitize-address) - if(${CMAKE_C_COMPILER_ID} STREQUAL "Clang") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-address-sanitizer.txt") - endif() - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fsanitize-address-use-after-scope") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") - else() - message(FATAL_ERROR "Missing support for address sanitizer!") - endif() - if (DEFINED SAVE_CMAKE_REQUIRED_FLAGS) - set(CMAKE_REQUIRED_FLAGS ${SAVE_CMAKE_REQUIRED_FLAGS}) - else() - unset(CMAKE_REQUIRED_FLAGS) - endif() - CHECK_C_COMPILER_FLAG ("-fno-omit-frame-pointer" fno-omit-frame-pointer) + if(fsanitize-blacklist) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-address-sanitizer.txt") + endif(fsanitize-blacklist) + + if(fsanitize-address-use-after-scope) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-address-use-after-scope") + endif(fsanitize-address-use-after-scope) + + else(fsanitize-address) + message(WARNING "Missing support for address sanitizer!") + endif(fsanitize-address) + if(fno-omit-frame-pointer) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer") endif() elseif(WITH_SANITIZE_MEMORY) - if (DEFINED CMAKE_REQUIRED_FLAGS) - set(SAVE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) - endif() set(CMAKE_REQUIRED_FLAGS "-fsanitize=memory") CHECK_C_COMPILER_FLAG ("-fsanitize=memory" fsanitize-memory) + CHECK_C_COMPILER_FLAG ("-fsanitize-blacklist=${CMAKE_BINARY_DIR}/foo.txt" fsanitize-blacklist) + CHECK_C_COMPILER_FLAG ("-fsanitize-memory-use-after-dtor" fsanitize-memory-use-after-dtor) + CHECK_C_COMPILER_FLAG ("-fsanitize-memory-track-origins" fsanitize-memory-track-origins) + unset(CMAKE_REQUIRED_FLAGS) + if(fsanitize-memory) - if(${CMAKE_C_COMPILER_ID} STREQUAL "Clang") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-memory-sanitizer.txt") - endif() - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory -fsanitize-memory-track-origins -fsanitize-memory-use-after-dtor") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=memory") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=memory") - else() - message(FATAL_ERROR "Missing support for memory sanitizer!") - endif() - if (DEFINED SAVE_CMAKE_REQUIRED_FLAGS) - set(CMAKE_REQUIRED_FLAGS ${SAVE_CMAKE_REQUIRED_FLAGS}) - else() - unset(CMAKE_REQUIRED_FLAGS) - endif() - CHECK_C_COMPILER_FLAG ("-fno-omit-frame-pointer" fno-omit-frame-pointer) + if(fsanitize-blacklist) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-memory-sanitizer.txt") + endif(fsanitize-blacklist) + + if (fsanitize-memory-use-after-dtor) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-memory-use-after-dtor") + endif(fsanitize-memory-use-after-dtor) + + if (fsanitize-memory-track-origins) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-memory-track-origins") + endif(fsanitize-memory-track-origins) + + else(fsanitize-memory) + message(WARNING "Missing support for memory sanitizer!") + endif(fsanitize-memory) + if(fno-omit-frame-pointer) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer") endif() elseif(WITH_SANITIZE_THREAD) - if (DEFINED CMAKE_REQUIRED_FLAGS) - set(SAVE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) - endif() - set(CMAKE_REQUIRED_FLAGS "-fsanitize=thread") CHECK_C_COMPILER_FLAG ("-fsanitize=thread" fsanitize-thread) + CHECK_C_COMPILER_FLAG ("-fsanitize-blacklist=${CMAKE_BINARY_DIR}/foo.txt" fsanitize-blacklist) + unset(CMAKE_REQUIRED_FLAGS) if(fsanitize-thread) - if(${CMAKE_C_COMPILER_ID} STREQUAL "Clang") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-thread-sanitizer.txt") - endif() + set(CMAKE_REQUIRED_FLAGS "-Werror -fsanitize=thread") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread") + if(fsanitize-blacklist) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-thread-sanitizer.txt") + endif(fsanitize-blacklist) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=thread") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread") - else() - message(FATAL_ERROR "Missing support for thread sanitizer!") - endif() - if (DEFINED SAVE_CMAKE_REQUIRED_FLAGS) - set(CMAKE_REQUIRED_FLAGS ${SAVE_CMAKE_REQUIRED_FLAGS}) - else() - unset(CMAKE_REQUIRED_FLAGS) - endif() + else(fsanitize-thread) + message(WARNING "Missing support for thread sanitizer!") + endif(fsanitize-thread) - CHECK_C_COMPILER_FLAG ("-fno-omit-frame-pointer" fno-omit-frame-pointer) if(fno-omit-frame-pointer) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer") endif() endif() + file(REMOVE ${CMAKE_BINARY_DIR}/foo.txt) + if (WITH_NO_UNDEFINED) - if (DEFINED CMAKE_REQUIRED_FLAGS) - set(SAVE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) - endif() set(CMAKE_REQUIRED_FLAGS "-Wl,--no-undefined") CHECK_C_COMPILER_FLAG (-Wl,--no-undefined no-undefined) - if (DEFINED SAVE_CMAKE_REQUIRED_FLAGS) - set(CMAKE_REQUIRED_FLAGS ${SAVE_CMAKE_REQUIRED_FLAGS}) - unset(SAVE_CMAKE_REQUIRED_FLAGS) - else() - unset(CMAKE_REQUIRED_FLAGS) - endif() + unset(CMAKE_REQUIRED_FLAGS) + if(no-undefined) SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined" ) endif() endif() + + set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS_SAVED}) endif() if(MSVC) @@ -469,7 +482,7 @@ if(WIN32) add_definitions(-D_WINSOCK_DEPRECATED_NO_WARNINGS) set(CMAKE_USE_RELATIVE_PATH ON) - if (${CMAKE_GENERATOR} MATCHES "NMake Makefile*") + if (${CMAKE_GENERATOR} MATCHES "NMake Makefile*" OR ${CMAKE_GENERATOR} MATCHES "Ninja*") set(CMAKE_PDB_BINARY_DIR ${CMAKE_BINARY_DIR}) elseif (${CMAKE_GENERATOR} MATCHES "Visual Studio*") set(CMAKE_PDB_BINARY_DIR "${CMAKE_BINARY_DIR}/\${CMAKE_INSTALL_CONFIG_NAME}") @@ -547,11 +560,6 @@ if(APPLE) if(NOT DEFINED CMAKE_OSX_ARCHITECTURES) set(CMAKE_OSX_ARCHITECTURES i386 x86_64) endif() - - if(IS_DIRECTORY /opt/local/include) - include_directories(/opt/local/include) - link_directories(/opt/local/lib) - endif() endif(IOS) # Temporarily disabled, causes the cmake script to be reexecuted, causing the compilation to fail. @@ -646,7 +654,13 @@ if(UNIX OR CYGWIN) if (HAVE_SYS_EVENTFD_H) check_symbol_exists(eventfd_read sys/eventfd.h WITH_EVENTFD_READ_WRITE) endif() + if (FREEBSD) + list(APPEND CMAKE_REQUIRED_INCLUDES ${EPOLLSHIM_INCLUDE_DIR}) + endif() check_include_files(sys/timerfd.h HAVE_SYS_TIMERFD_H) + if (FREEBSD) + list(REMOVE_ITEM CMAKE_REQUIRED_INCLUDES ${EPOLLSHIM_INCLUDE_DIR}) + endif() check_include_files(poll.h HAVE_POLL_H) list(APPEND CMAKE_REQUIRED_LIBRARIES m) check_symbol_exists(ceill math.h HAVE_MATH_C99_LONG_DOUBLE) @@ -744,6 +758,22 @@ set(GSM_FEATURE_TYPE "OPTIONAL") set(GSM_FEATURE_PURPOSE "codec") set(GSM_FEATURE_DESCRIPTION "GSM audio codec library") +set(LAME_FEATURE_TYPE "OPTIONAL") +set(LAME_FEATURE_PURPOSE "codec") +set(LAME_FEATURE_DESCRIPTION "lame MP3 audio codec library") + +set(FAAD2_FEATURE_TYPE "OPTIONAL") +set(FAAD2_FEATURE_PURPOSE "codec") +set(FAAD2_FEATURE_DESCRIPTION "FAAD2 AAC audio codec library") + +set(FAAC_FEATURE_TYPE "OPTIONAL") +set(FAAC_FEATURE_PURPOSE "codec") +set(FAAC_FEATURE_DESCRIPTION "FAAC AAC audio codec library") + +set(SOXR_FEATURE_TYPE "OPTIONAL") +set(SOXR_FEATURE_PURPOSE "codec") +set(SOXR_FEATURE_DESCRIPTION "SOX audio resample library") + set(GSSAPI_FEATURE_TYPE "OPTIONAL") set(GSSAPI_FEATURE_PURPOSE "auth") set(GSSAPI_FEATURE_DESCRIPTION "add kerberos support") @@ -844,13 +874,54 @@ find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DE find_feature(x264 ${X264_FEATURE_TYPE} ${X264_FEATURE_PURPOSE} ${X264_FEATURE_DESCRIPTION}) find_feature(OpenH264 ${OPENH264_FEATURE_TYPE} ${OPENH264_FEATURE_PURPOSE} ${OPENH264_FEATURE_DESCRIPTION}) find_feature(GSM ${GSM_FEATURE_TYPE} ${GSM_FEATURE_PURPOSE} ${GSM_FEATURE_DESCRIPTION}) +find_feature(LAME ${LAME_FEATURE_TYPE} ${LAME_FEATURE_PURPOSE} ${LAME_FEATURE_DESCRIPTION}) +find_feature(FAAD2 ${FAAD2_FEATURE_TYPE} ${FAAD2_FEATURE_PURPOSE} ${FAAD2_FEATURE_DESCRIPTION}) +find_feature(FAAC ${FAAC_FEATURE_TYPE} ${FAAC_FEATURE_PURPOSE} ${FAAC_FEATURE_DESCRIPTION}) +find_feature(soxr ${SOXR_FEATURE_TYPE} ${SOXR_FEATURE_PURPOSE} ${SOXR_FEATURE_DESCRIPTION}) find_feature(GSSAPI ${GSSAPI_FEATURE_TYPE} ${GSSAPI_FEATURE_PURPOSE} ${GSSAPI_FEATURE_DESCRIPTION}) +if ((WITH_FFMPEG OR WITH_DSP_FFMPEG) AND NOT FFMPEG_FOUND) + message(FATAL_ERROR "FFMPEG support requested but not detected") +endif() +set(WITH_FFMPEG ${FFMPEG_FOUND}) + +# Version check, if we have detected FFMPEG but the version is too old +# deactivate it as sound backend. +if (WITH_DSP_FFMPEG) + # Deactivate FFmpeg backend for sound, if the version is too old. + # See libfreerdp/codec/dsp_ffmpeg.h + file(STRINGS "${AVCODEC_INCLUDE_DIR}/libavcodec/version.h" AV_VERSION_FILE REGEX "LIBAVCODEC_VERSION_M[A-Z]+[\t ]*[0-9]+") + FOREACH(item ${AV_VERSION_FILE}) + STRING(REGEX MATCH "LIBAVCODEC_VERSION_M[A-Z]+[\t ]*[0-9]+" litem ${item}) + IF(litem) + string(REGEX REPLACE "[ \t]+" ";" VSPLIT_LINE ${litem}) + list(LENGTH VSPLIT_LINE VSPLIT_LINE_LEN) + if (NOT "${VSPLIT_LINE_LEN}" EQUAL "2") + message(ERROR "invalid entry in libavcodec version header ${item}") + endif(NOT "${VSPLIT_LINE_LEN}" EQUAL "2") + list(GET VSPLIT_LINE 0 VNAME) + list(GET VSPLIT_LINE 1 VVALUE) + set(${VNAME} ${VVALUE}) + ENDIF(litem) + ENDFOREACH(item ${AV_VERSION_FILE}) + + set(AVCODEC_VERSION "${LIBAVCODEC_VERSION_MAJOR}.${LIBAVCODEC_VERSION_MINOR}.${LIBAVCODEC_VERSION_MICRO}") + if (AVCODEC_VERSION VERSION_LESS "57.48.101") + message(WARNING "FFmpeg version detected (${AVCODEC_VERSION}) is too old. (Require at least 57.48.101 for sound). Deactivating") + set(WITH_DSP_FFMPEG OFF) + endif() +endif (WITH_DSP_FFMPEG) + +if (WITH_OPENH264 AND NOT OPENH264_FOUND) + message(FATAL_ERROR "OpenH264 support requested but not detected") +endif() +set(WITH_OPENH264 ${OPENH264_FOUND}) + if ( (WITH_GSSAPI) AND (NOT GSS_FOUND)) message(WARNING "-DWITH_GSSAPI=ON is set, but not GSSAPI implementation was found, disabling") elseif(WITH_GSSAPI) - if(GSS_FLAVOUR STREQUAL "MIT") + if(GSS_FLAVOUR STREQUAL "MIT") add_definitions("-DWITH_GSSAPI -DWITH_GSSAPI_MIT") if(GSS_VERSION_1_13) add_definitions("-DHAVE_AT_LEAST_KRB_V1_13") @@ -926,7 +997,9 @@ if (APPLE) set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks") else (APPLE) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) - set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}:\$ORIGIN/..") + if (NOT FREEBSD) + set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}:\$ORIGIN/..") + endif() endif(APPLE) if (BUILD_SHARED_LIBS) @@ -969,6 +1042,10 @@ else() set(PRIVATE_KEYWORD "PRIVATE") endif() +if(BUILD_SHARED_LIBS) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWINPR_DLL") +endif() + add_subdirectory(winpr) # Sub-directories diff --git a/ChangeLog b/ChangeLog index 64ceaa2..6ae0546 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,2951 @@ +2018-11-20 11:43:51 +0100 akallabeth (e21b72c95) + + * Merge pull request #5032 from bmiklautz/rc4 + +2018-11-12 14:46:01 +0100 Bernhard Miklautz (cc801eded) + + * new: version 2.0.0-rc4 + +2018-11-20 10:20:43 +0000 Bernhard Miklautz (98490b079) + + * Merge pull request #5031 from akallabeth/cve_fixes_final + +2018-10-22 16:59:28 +0200 Armin Novak (eb57ed3a3) + + * Refactored ntlm_av_pairs API + +2018-10-22 17:51:26 +0200 Armin Novak (17c363a51) + + * Fixed CVE-2018-8784 + +2018-10-22 16:52:21 +0200 Armin Novak (d1112c279) + + * Fixed CVE-2018-8788 + +2018-10-22 16:30:20 +0200 Armin Novak (09b9d4f19) + + * Fixed CVE-2018-8787 + +2018-10-22 16:25:13 +0200 Armin Novak (445a5a42c) + + * Fixed CVE-2018-8786 + +2018-10-22 16:20:34 +0200 Armin Novak (602f4a2e1) + + * Fixed CVE-2018-8785 + +2018-10-22 16:00:03 +0200 Armin Novak (2ee663f39) + + * Fixed CVE-2018-8789 + +2018-11-20 10:07:30 +0000 Bernhard Miklautz (ef0c7e81a) + + * Merge pull request #4953 from akallabeth/region_signed + +2018-11-20 10:53:40 +0100 Martin Fleisz (38091fc34) + + * Merge pull request #5030 from akallabeth/pointer_cache_optional + +2018-11-20 09:09:52 +0100 Armin Novak (666ef4ab3) + + * Fix #4864: Register pointer cache after PostConnect is called + +2018-11-20 09:38:02 +0100 Armin Novak (3e2caa88a) + + * Fixed invalid NULL check + +2018-11-20 09:00:39 +0100 akallabeth (a4001a047) + + * Merge pull request #5029 from mcsong/master + +2018-11-19 14:38:48 -0800 mcsong (d7ab198a6) + + * added korean translation + +2018-11-19 17:24:24 +0100 Armin Novak (53fdea845) + + * Clip coordinates for lineTo and polyLine + +2018-11-19 17:24:06 +0100 Armin Novak (d75c464db) + + * Fixed signed/unsigned warnings. + +2018-11-19 13:58:53 +0100 Armin Novak (75d532f87) + + * Fixed glyph cache bounds setting. + +2018-11-13 17:06:09 +0100 Armin Novak (e94ed7d76) + + * Fixed gdi_BitBlt coordinate clipping. + +2018-10-22 14:12:22 +0200 Armin Novak (a078d8714) + + * Fixed opaque rect bounding rectangle. + +2018-10-19 17:02:33 +0200 akallabeth (b6eca4fc5) + + * signed gdi regions to adjust negative coordinates + +2018-11-19 10:20:52 +0100 Martin Fleisz (b216520d5) + + * Merge pull request #5021 from akallabeth/profiler_api_rework + +2018-11-19 09:15:14 +0000 Bernhard Miklautz (b7354ce43) + + * Merge pull request #4940 from akallabeth/check_window_order_support + +2018-11-19 08:57:53 +0000 Bernhard Miklautz (3eb46444e) + + * Merge pull request #5025 from DustPuppyNet/openssl_1_1_1 + +2018-11-18 14:09:37 +0000 Christian Gall (fffe4f077) + + * * remove obsolete SSLv23_client_method in tls_connect() * set min + TLS Version + +2018-11-17 18:47:08 +0000 Bernhard Miklautz (621ade9b8) + + * Merge pull request #5023 from ileGITimo/master + +2018-11-17 06:32:52 -0800 ileGITimo (d5dd983bc) + + * call xf_SetWindowTitle before XMapWindow, so window manager can act + on window name + +2018-11-15 17:52:43 +0100 Armin Novak (d2e1248b0) + + * Fixed profiler API + +2018-11-15 16:46:57 +0000 Bernhard Miklautz (fe1a79759) + + * Merge pull request #5018 from hardening/windowpos + +2018-11-15 15:54:56 +0000 Bernhard Miklautz (010e3485c) + + * Merge pull request #4989 from akallabeth/dsp_encode_resample + +2018-11-15 15:25:25 +0000 Bernhard Miklautz (d6dea852b) + + * Merge pull request #4976 from hardening/rfx_flush + +2018-11-15 13:48:22 +0000 Bernhard Miklautz (b8cf70b13) + + * Merge pull request #4964 from akallabeth/rdg_fixes + +2018-11-15 14:40:03 +0100 David Fort (e118d14f6) + + * cmdline: add window-position argument to set initial window + position + +2018-10-19 11:14:09 +0200 Armin Novak (4d7bece6e) + + * Fixed order mask + +2018-10-18 17:23:06 +0200 Armin Novak (dd80a0978) + + * Allow window orders with AllowUnanouncedOrdersFromServer + +2018-10-18 10:55:48 +0200 Armin Novak (c0b13cf43) + + * Added checks for order type window support. + +2018-11-15 08:50:56 +0000 Bernhard Miklautz (d91549171) + + * Merge pull request #5012 from akallabeth/rail_app_icons + +2018-11-15 08:43:54 +0100 akallabeth (cf2c8ef6a) + + * Merge pull request #5015 from chipitsine/cleanup + +2018-11-15 01:54:39 +0500 Ilya Shipitsin (77323d6f1) + + * remove not needed check + +2018-11-15 01:51:44 +0500 Ilya Shipitsin (be8f70998) + + * remove not needed check + +2018-11-14 13:45:31 +0100 akallabeth (268a2c0cf) + + * Merge pull request #4979 from hardening/CAL + +2018-11-14 13:35:42 +0100 Martin Fleisz (1f5c4e223) + + * Merge pull request #5009 from akallabeth/rdp_version_update + +2018-11-14 13:29:03 +0100 akallabeth (50395ff57) + + * Merge pull request #5013 from bmiklautz/sspi_symbols + +2018-11-13 14:46:51 +0100 Armin Novak (5490ceb4e) + + * Fixed source format for freerdp_dsp_encode in + rdpsnd_server_send_wave_pdu + +2018-11-13 14:04:43 +0100 Armin Novak (e5197f529) + + * Add soxr library and include paths. + +2018-11-13 12:29:19 +0100 Armin Novak (9766161f1) + + * Added missing define guards. + +2018-11-13 11:06:38 +0100 Armin Novak (5b363e72a) + + * Allow building without libsoxr support. + +2018-11-13 11:03:09 +0100 Armin Novak (6af56458a) + + * Marked custom ADPCM codecs experimental. + +2018-11-13 11:00:39 +0100 Armin Novak (0f45a570f) + + * Added fallback for supported sample rates if original not + supported. Added format compatibility check between + recording input and destination. + +2018-11-13 10:59:41 +0100 Armin Novak (93eea2412) + + * Fixed possible NULL pointer dereference + +2018-11-13 10:59:30 +0100 Armin Novak (b362b61a1) + + * Added libsoxr based resampling. + +2018-11-13 09:13:52 +0100 Armin Novak (e93aab2f7) + + * Added CMake detection support for libsoxr + +2018-11-09 10:15:14 +0100 Armin Novak (ab15e3403) + + * Refactored freerdp_dsp_resample, checks now done internally. + +2018-11-09 10:05:11 +0100 Armin Novak (83f959ce6) + + * Fixed format issues with server sound channel (review by @llysz) + +2018-11-09 09:08:06 +0100 Armin Novak (60025dde8) + + * Fixed unused function warnings when FFMPEG backend is used. + +2018-11-07 14:14:15 +0100 Armin Novak (e8e4800c5) + + * Added resampling to freerdp_dsp_encode. + +2018-11-14 11:57:13 +0000 Bernhard Miklautz (e980d20e8) + + * Merge pull request #4973 from Devolutions/fix_drive_redirection + +2018-11-14 11:39:23 +0000 Bernhard Miklautz (44ead4cfe) + + * Merge pull request #5001 from akallabeth/mac_clipboard_fix + +2018-11-14 12:19:36 +0100 Bernhard Miklautz (a9bcc07d2) + + * fix [winpr/sspi]: export symbols on all systems + +2018-11-14 11:29:44 +0100 Armin Novak (98a537d05) + + * Better description and formatting for update_read_icon_info + +2018-11-14 11:06:23 +0100 Armin Novak (7e12955c5) + + * Made all internal functions static. + +2018-11-14 11:04:59 +0100 Armin Novak (43e17c975) + + * Fixed color conversion, log level and buffer types + +2018-11-14 11:03:59 +0100 Armin Novak (e500abc09) + + * Fixed rail_string_to_unicode_string size calculation. + +2018-11-10 14:43:36 +0200 ilammy (9292b2231) + + * xfreerdp: set _NET_WM_ICON to RAIL app icon + +2018-11-10 11:51:30 +0200 ilammy (8163b6d1c) + + * xfreerdp: add RAIL icon cache + +2018-11-10 22:09:20 +0200 ilammy (7a2b6e130) + + * libfreerdp-core: fix reading TS_ICON_INFO + +2018-11-14 10:14:48 +0100 Armin Novak (138eb13fe) + + * Updated RDP_VERSION definitions. + +2018-11-13 14:39:39 +0100 akallabeth (ca6d1d591) + + * Merge pull request #5005 from bmiklautz/nightly_build + +2018-11-13 13:59:41 +0100 Bernhard Miklautz (bbd6a3e6c) + + * fix [rpm/freerdp-nightly]: build dependencies + +2018-11-13 12:22:09 +0100 Armin Novak (ecac99834) + + * Fixed rdg bio cleanup. + +2018-11-13 11:24:04 +0100 Armin Novak (3c35a098f) + + * Fixed direct rdg front bio access. + +2018-11-13 09:30:47 +0100 Armin Novak (e070bbea8) + + * Fixed leaks in rdg_send_channel_create + +2018-11-12 16:48:31 +0100 Armin Novak (342ff8cf0) + + * Fixed broken server name packet size + +2018-11-12 15:40:10 +0100 Armin Novak (15a41586a) + + * Don't read content length in + VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT + +2018-11-12 16:29:28 +0100 Armin Novak (90d2e4260) + + * Fixed ntlm_authenticate, split return from continue flag. + +2018-11-07 11:25:09 +0100 Armin Novak (4e0b4d709) + + * Fixed static INT_MAX checks, replaced with assert. + +2018-10-24 16:49:25 +0200 Armin Novak (398a33af6) + + * Fixed all warnings in rdg module + +2018-10-24 15:46:18 +0200 Armin Novak (9078b0deb) + + * Fixed extern declaration of rpc_bind p_uuid_t variables. + +2018-10-24 15:42:44 +0200 Armin Novak (b4fc0c75c) + + * Made rdpRdp opaque + +2018-10-31 10:27:31 +0100 David Fort (b6e6575bf) + + * license: support CAL license + +2018-11-12 13:55:36 +0100 Martin Fleisz (097ac0ee1) + + * Merge pull request #4997 from akallabeth/use_bio_free_all + +2018-11-12 08:35:04 +0100 Armin Novak (738aa5623) + + * Fixed #4995: Don't forget to send the NULL of the clipboard string. + +2018-11-09 12:25:55 +0000 Bernhard Miklautz (c5c1bac31) + + * Merge pull request #4960 from akallabeth/interleaved_fix + +2018-11-09 12:18:51 +0100 Armin Novak (fff2454ae) + + * Make VS2010 happy, reworked UNROLL defines. + +2018-11-09 11:51:20 +0100 Armin Novak (6e61dd9d9) + + * Unroll bBits loops as well. + +2018-11-09 12:07:43 +0100 Martin Fleisz (6d6a2959c) + + * Merge pull request #4968 from akallabeth/timezone_updates + +2018-11-09 11:58:04 +0100 Martin Fleisz (a7f0da244) + + * Merge pull request #4961 from akallabeth/align_malloc_fix + +2018-11-09 11:32:28 +0100 Armin Novak (7e932bbfa) + + * Readded loop unrolling. + +2018-10-24 10:59:54 +0200 Armin Novak (71036fe0b) + + * Fixed #2039: Check for overflow in calculations. + +2018-11-08 17:41:56 +0100 Armin Novak (cf8bc72dc) + + * Fixed profiler naming in tests. + +2018-11-08 17:21:28 +0100 Armin Novak (9e2c20377) + + * Fixed various issues with freerdp_bitmap_compress and + interleaved_compress + +2018-11-08 17:20:31 +0100 Armin Novak (c0c1d064b) + + * Added a unit test for interleaved codec compression. + +2018-11-08 15:33:40 +0100 Martin Fleisz (9400bdccd) + + * Merge pull request #4996 from bmiklautz/tls_security_level + +2018-11-08 12:09:49 +0100 Armin Novak (5f4843191) + + * Replaced BIO_free with BIO_free_all + +2018-11-08 11:13:57 +0100 Bernhard Miklautz (8be6ec972) + + * fix [cmdline]: parameter parsing + +2018-11-08 11:01:56 +0100 Bernhard Miklautz (1222e7060) + + * new [crypto/tls]: add support to set tls security level + +2018-11-08 10:08:03 +0000 Bernhard Miklautz (1f2a22d0d) + + * Merge pull request #4994 from akallabeth/bio_uninit_fix + +2018-11-07 17:01:28 +0100 Armin Novak (5eca5ebde) + + * Fixed #4993: Allow uninitialized bio socket in + transport_bio_simple_uninit + +2018-11-07 16:11:02 +0100 akallabeth (cf43406dc) + + * Merge pull request #4982 from bmiklautz/ctest_asan_fixes + +2018-10-24 17:40:05 +0200 Armin Novak (6a2d49e0e) + + * Simplified timezone update handling: + +2018-11-07 12:00:49 +0100 Armin Novak (a544776bd) + + * Simplified code, moved bounds check out of loops. + +2018-10-23 10:33:45 +0200 Armin Novak (10d3ee131) + + * Fixed #4954: Check destination buffer bounds. + +2018-11-06 13:51:53 +0100 Martin Fleisz (76c91ee51) + + * Merge pull request #4985 from informatimago/issue-4983 + +2018-11-06 11:20:02 +0100 Pascal J. Bourguignon (6f2caef77) + + * Fix Issue #4983 : Increased size of buffer to encrypt hash with + kerberos. + +2018-11-05 15:43:12 +0100 Bernhard Miklautz (37f818173) + + * fix [libfreerdp/codec]: heap buffer overflow in + TestFreeRDPCodecClear + +2018-11-05 13:46:05 +0100 Bernhard Miklautz (649404dd2) + + * fix [libfreerdp/crypto]: memory leak in Test_x509_cert_info + +2018-11-05 12:29:06 +0100 Bernhard Miklautz (472f7ea93) + + * fix [winpr/util]: memory leak in TestCmdLine + +2018-11-05 10:44:01 +0000 Bernhard Miklautz (aecc77cd7) + + * Merge pull request #4969 from akallabeth/covscan_fix + +2018-11-05 09:57:04 +0000 Bernhard Miklautz (a95a55a0c) + + * Merge pull request #4980 from hardening/logon_infov2_fix + +2018-11-01 10:45:56 +0100 David Fort (1a50a4833) + + * fix uninitialised variable + +2018-10-31 11:26:19 +0000 Bernhard Miklautz (29d3fea3d) + + * Merge pull request #4974 from Devolutions/android_timezone_fix + +2018-10-31 11:12:05 +0000 Bernhard Miklautz (62a1967ad) + + * Merge pull request #4977 from hardening/nego_flags + +2018-10-26 10:37:10 +0200 David Fort (548025bcc) + + * nego: add new flags + +2018-10-31 09:59:56 +0100 David Fort (af195864e) + + * remotefx: fix rlgr last bits of encoder + +2018-10-30 16:47:06 -0400 Jonathan Lafontaine (610a882f1) + + * remove unsupported call to fseek when file is opened with popen + +2018-10-29 10:17:42 -0400 Jonathan Lafontaine (35d7a1e38) + + * Allow fixed drive redirection on Windows (a:, c:, ...) and fix + macos drive duplication. + +2018-10-29 14:54:55 +0100 Martin Fleisz (7b0f4f5dc) + + * Merge pull request #4907 from akallabeth/transport_write_leak_fix + +2018-10-29 10:26:04 +0000 Bernhard Miklautz (242f7f231) + + * Merge pull request #4962 from akallabeth/wextra_fixes + +2018-10-25 15:54:21 +0200 akallabeth (c3c9783e6) + + * Merge pull request #4970 from hardening/uwac_fixes + +2018-10-25 15:48:48 +0200 Armin Novak (fffd352f8) + + * Fixed warnings in Stream test. + +2018-10-25 15:48:06 +0200 Armin Novak (b7f272cd1) + + * Fixed casts in Data_Read macros. + +2018-10-25 15:20:18 +0200 David Fort (0b2ea08f7) + + * uwac: change seat API to not reference disposed UwacSeat + +2018-10-24 17:24:35 +0200 Armin Novak (423d54d75) + + * Fixed signedness casts. + +2018-10-24 17:22:43 +0200 Armin Novak (9633e4576) + + * Fixed signedness of MoniorCount + +2018-10-25 13:19:22 +0200 Armin Novak (6339c43c8) + + * Fixed sockfd/socketBio resource leak. + +2018-10-25 13:13:14 +0200 Armin Novak (42014e80d) + + * Fixed sockfd/socketBio resource leak. + +2018-10-25 13:08:16 +0200 Armin Novak (7aebf8ebd) + + * Silence code analyzers, check correct variable for NULL. + +2018-10-25 13:08:00 +0200 Armin Novak (f269a0ce5) + + * Fixed sockfd/socketBio resource leak. + +2018-10-25 12:49:42 +0200 Armin Novak (847ee233f) + + * Fixed resource leak in rpc_ntlm_http_request + +2018-10-24 16:50:05 +0200 Armin Novak (97e68deea) + + * Fixed initialisation in DEFINE_EVENT_ENTRY define + +2018-10-24 14:36:12 +0200 Armin Novak (987ca5ec6) + + * Fixed another bunch of warnings. + +2018-10-24 13:20:46 +0200 Armin Novak (02f68c35b) + + * Fixed -Wextra sign warnings + +2018-10-24 13:17:14 +0200 Armin Novak (86f08981e) + + * Fixed warnings of uninitialized struct values. + +2018-10-24 13:17:04 +0200 Armin Novak (46d6aa4e2) + + * Fixed cast warnings for thread wrapper + +2018-10-24 13:05:49 +0200 Armin Novak (2a4b47aaa) + + * Changed size iterator variables to size_t + +2018-10-23 12:33:13 +0200 Armin Novak (6ccaafe2d) + + * Fixed default return value for fastpath_send_multiple_input_pdu + +2018-10-23 12:03:03 +0200 akallabeth (d3c1db174) + + * Merge pull request #4947 from akallabeth/http_gw_fix + +2018-10-23 10:40:09 +0200 akallabeth (76e81c615) + + * Merge pull request #4958 from nfedera/nf-fix-alsapulse-wrn-err + +2018-10-23 09:45:20 +0200 Norbert Federa (af992f4ce) + + * channels/client: fix alsa/pulse warning and checks + +2018-10-23 09:28:00 +0200 Norbert Federa (a7022e9a5) + + * Merge pull request #4957 from akallabeth/wave_2_pdu_fix + +2018-10-22 21:16:36 +0200 akallabeth (16d37b1a1) + + * Merge pull request #4932 from hardening/stream_static + +2018-10-22 14:53:46 +0200 Armin Novak (fe7a37dcb) + + * Cleaned up resource cleanup for rdpsnd alsa backend. + +2018-10-22 12:50:21 +0000 Bernhard Miklautz (0e9b26c1d) + + * Merge pull request #4796 from akallabeth/groegera_fixes + +2018-10-22 14:41:59 +0200 Armin Novak (900abb61f) + + * Fixed memory leak in update_recv_surfcmd_surface_bits + +2018-10-22 13:02:00 +0200 Armin Novak (3ed50aaca) + + * Implemented rdpsnd_pulse_get_volume + +2018-10-22 12:27:19 +0200 Armin Novak (9ff17dc0f) + + * fixed return value check in rdpsnd_recv_volume_pdu + +2018-10-22 12:16:18 +0200 Armin Novak (e2e1071ff) + + * Seal length in wave pdu alignment. + +2018-10-22 12:00:07 +0200 Armin Novak (1a015612a) + + * Align wave pdu size + +2018-10-22 11:59:42 +0200 Armin Novak (fb76f88ca) + + * Added missing length check and log message information. + +2018-10-22 10:27:16 +0200 Armin Novak (3d49697d1) + + * Improved debug logging for sound device handling. + +2018-10-22 10:18:17 +0200 Armin Novak (ff7e91fed) + + * Removed unnecessary pulse context check. + +2018-10-22 10:04:02 +0200 Armin Novak (03dcfaf8d) + + * Unified sound device reopen in a single function. + +2018-10-19 17:13:21 +0200 akallabeth (c251bdc11) + + * Merge pull request #4952 from eledoux/master + +2018-10-19 14:00:14 +0200 akallabeth (b8ff18f37) + + * Merge pull request #4951 from nfedera/nf-fix-fnobjnew-fnstylecasts + +2018-10-19 13:47:42 +0200 akallabeth (1929e3d1e) + + * Merge pull request #4949 from bmiklautz/floatbar_warning + +2018-10-19 13:00:51 +0200 akallabeth (a263da002) + + * Merge pull request #4950 from bmiklautz/cleanup_pr_4581p2 + +2018-10-19 12:52:14 +0200 Armin Novak (b9933e7af) + + * Read byte by byte, the alignment may otherwise be broken. + +2018-10-19 11:59:28 +0200 Armin Novak (5a747b118) + + * Read http request in 4byte chunks until '\r\n\r\n' is found + +2018-10-19 11:56:56 +0200 Emmanuel Ledoux (33c7f6590) + + * fixed partial reads + +2018-10-19 11:39:22 +0200 Armin Novak (d05684a50) + + * Properly parse ContentType to find length. + +2018-10-19 10:33:50 +0200 Bernhard Miklautz (9b353202a) + + * fix [x11]: compiler warnings in floatbar + +2018-10-19 11:30:01 +0200 Norbert Federa (0572572eb) + + * fix issue with fnObjectFree and related casts + +2018-10-19 11:11:44 +0200 Bernhard Miklautz (7290e3f2b) + + * fix [cache/pointer]: add missing callback checks + +2018-10-19 11:10:23 +0200 MartinHaimberger (1dc3c91a1) + + * Merge pull request #4948 from bmiklautz/cleanup_pr_4581 + +2018-10-18 14:32:08 +0200 Bernhard Miklautz (e114ee44e) + + * new [cache/pointer]: don't require pointer functions to be set + +2018-10-18 16:58:53 +0200 Armin Novak (7e397d0f1) + + * Fixed http gateway body length read. + +2018-10-18 16:40:22 +0200 akallabeth (3d0ccb3f5) + + * Merge pull request #4946 from + mmattes/fix/floatbar_app_check_missing + +2018-10-18 15:37:24 +0200 akallabeth (6f14018a2) + + * Merge pull request #4945 from mmattes/fix/transferEncoding + +2018-10-18 15:33:01 +0200 Markus Mattes (a235b44f6) + + * added missing check for remote app where no floatbar exists + +2018-10-18 14:11:18 +0200 Norbert Federa (850d2dbda) + + * Merge pull request #4942 from akallabeth/rail_fixes_2.0 + +2018-10-18 14:08:23 +0200 Norbert Federa (5ef243f91) + + * Merge pull request #4941 from + nfedera/nf-remove-stale-valgrind-macro + +2018-10-18 14:08:01 +0200 Norbert Federa (d9a4ae831) + + * Merge pull request #4938 from akallabeth/warning_fixes_master + +2018-10-18 13:59:49 +0200 Markus Mattes (6d5b88cda) + + * transferEncoding can be NULL, verification happens in line 348 + +2018-10-18 12:34:10 +0200 Armin Novak (5b70142ec) + + * Fixed read_altsec_order ORDER_TYPE_WINDOW + +2018-10-18 12:33:06 +0200 Armin Novak (8bdb5d771) + + * Fixed order to string format string. + +2018-10-18 11:45:18 +0200 Norbert Federa (d201deede) + + * gateway/rpc: remove stale valgrind macro + +2018-10-18 11:12:59 +0200 Martin Fleisz (eea5e2085) + + * Merge pull request #4939 from + nfedera/nf-fix-rdpsnd_server_send_formats + +2018-10-18 10:41:03 +0200 Armin Novak (2e3832af9) + + * Fixed TSG stream alignment (4 or 8) + +2018-10-18 10:15:24 +0200 Norbert Federa (d35470f8a) + + * rdpsnd: always call rdpsnd_server_send_formats + +2018-10-18 10:15:51 +0200 Armin Novak (dc197d4dd) + + * Fixed tsg abort condition. + +2018-10-18 09:09:30 +0200 Armin Novak (88d310ff2) + + * Fixed compiler warnings (casts, ...) + +2018-10-18 09:06:55 +0200 Armin Novak (554e18780) + + * USe const compare function pointer arguments + +2018-10-16 11:33:03 +0200 David Fort (13e2a8834) + + * winpr: add some functions to use wStream in a static way + +2018-10-17 17:27:29 +0200 akallabeth (305f5d1bd) + + * Merge pull request #4600 from andreesteve/xfullscreen + +2018-10-17 17:16:28 +0200 MartinHaimberger (558a03f60) + + * Merge pull request #4937 from akallabeth/server_rdpsnd_get_formats + +2018-10-17 16:17:41 +0200 Armin Novak (e319ec5bd) + + * Fixed missing return in server_rdpsnd_get_formats + +2018-10-17 16:02:28 +0200 Martin Fleisz (e46d1d95f) + + * Merge pull request #4926 from akallabeth/primary_order_checks + +2018-10-17 15:01:22 +0200 akallabeth (fbceb7c75) + + * Merge pull request #4478 from smalleel/master + +2018-10-02 13:18:13 +0200 Armin Novak (991f051a6) + + * Fixed stream release for transport_write + +2018-10-02 14:22:27 +0200 Armin Novak (3416d1bde) + + * Reset stream length to capacity in StreamPool_Take + +2018-10-17 14:40:00 +0200 MartinHaimberger (6f6581cdd) + + * Merge pull request #4933 from akallabeth/planar_alpha_fix + +2018-10-17 14:35:17 +0200 MartinHaimberger (741a032b9) + + * Merge pull request #4936 from akallabeth/gw_leak_fix + +2018-10-17 14:16:16 +0200 Armin Novak (aefb7728f) + + * Removed debug log entries, simplified order support check. + +2018-10-17 13:19:33 +0200 Armin Novak (f91590ecb) + + * Fixed bugs detected during scanbuild run + +2018-10-17 12:23:10 +0200 akallabeth (8fe3ac5d2) + + * Merge pull request #4902 from akallabeth/gw_refactor_3 + +2018-10-17 12:19:03 +0200 akallabeth (e54af8efa) + + * Merge pull request #4927 from akallabeth/cmdline_fixes + +2018-10-17 12:15:57 +0200 Armin Novak (7b860ce96) + + * Add command line option /relax-order-checks + +2018-10-17 11:36:32 +0200 Armin Novak (a432a297c) + + * Fixed division by 0 if invalid formats are used. + +2018-10-17 11:32:56 +0200 akallabeth (5778bf102) + + * Merge pull request #4891 from akallabeth/rail_fixes + +2018-10-17 10:47:23 +0200 Armin Novak (10cc31997) + + * Announce glyph orders if glyph cache is activated. + +2018-10-17 10:09:37 +0200 Armin Novak (c0d38778f) + + * Fixed length sanity check. + +2018-10-17 10:09:27 +0200 Armin Novak (4d124cf5d) + + * Fixed order requirements. + +2018-10-16 17:29:10 +0200 Armin Novak (777bfe5c4) + + * Fixed const correctness of arguments. + +2018-10-16 17:26:57 +0200 Armin Novak (75517c06f) + + * Added parameter checks. + +2018-10-16 17:23:24 +0200 Armin Novak (bbcba568f) + + * Added parameter checks. + +2018-10-16 17:14:56 +0200 Armin Novak (d2e08c0aa) + + * Fixed missing argument check. + +2018-10-16 17:10:03 +0200 Armin Novak (3629a84d3) + + * Fixed missing input validation. + +2018-10-16 17:09:29 +0200 Armin Novak (cab2e2857) + + * Fixed missing value check + +2018-10-16 16:10:17 +0200 Armin Novak (c51ca89d9) + + * Fixed glyph cache + +2018-10-16 15:56:17 +0200 Armin Novak (5ea4a7d3b) + + * Proper order checks. + +2018-10-16 09:09:05 -0400 Marc-André Moreau (ce234411c) + + * Merge pull request #4914 from Devolutions/winpr-dll-export + +2018-10-16 13:59:37 +0200 Armin Novak (16d553a75) + + * Check if incoming secondary alternate orders have been activated. + +2018-10-16 13:48:43 +0200 Armin Novak (711da861e) + + * Check if incoming secondary orders have been activated. + +2018-10-16 13:48:29 +0200 Armin Novak (88bd26213) + + * Send brush support level from settings. + +2018-10-16 13:02:15 +0200 Armin Novak (c99434691) + + * For every order check if it is activated in settings before + processing. + +2018-10-16 12:46:44 +0200 Armin Novak (fb87f6d0b) + + * Added a warning that the server sent an unsupported order + +2018-10-16 12:36:08 +0200 Armin Novak (e4b24aa31) + + * Fixed arguments to *adust + +2018-10-16 12:17:25 +0200 Armin Novak (91107beb6) + + * Separate alpha handling for planar codec + +2018-10-16 10:05:33 +0200 Armin Novak (a29bc16af) + + * Siplified planar alpha / non alpha paths + +2018-10-16 08:45:06 +0200 Armin Novak (7d8e6377d) + + * Fixed a memory leak in cleaning up brushes. + +2018-10-15 16:34:44 +0200 Armin Novak (14321a2d5) + + * Adjust rectangles where appropriate. + +2018-10-15 16:33:56 +0200 Armin Novak (3920c570d) + + * Fixed memory leak with audio formats. + +2018-10-15 15:27:17 +0200 Armin Novak (e5d60370b) + + * Fixed MultiOpaqueRect + +2018-10-15 15:23:04 +0200 Armin Novak (479233ced) + + * Fix bounding rectangle of OpaqueRect + +2018-10-15 15:22:50 +0200 Armin Novak (ca3fb2623) + + * Deactivated unimplemented orders. + +2018-10-15 14:36:03 +0200 Armin Novak (63823f54e) + + * Removed checks for LineTo, that is handled by the drawing routines + +2018-10-15 14:30:38 +0200 Armin Novak (f88ed950d) + + * Fixed various issues with primary orders. + +2018-10-15 13:56:19 +0200 Armin Novak (83fba667c) + + * Fixed logging. + +2018-10-15 13:20:47 +0200 Armin Novak (8cfffcc02) + + * Use dynamic logging and fix compiler warnings. + +2018-10-15 13:15:57 +0200 Armin Novak (ed02832a8) + + * Added altsec return value checks. + +2018-10-15 13:10:48 +0200 Armin Novak (09bef3bab) + + * Unified logging. + +2018-10-15 11:51:16 +0200 Armin Novak (972959087) + + * Fixed command line setting of flags, unified string replace + +2018-10-15 10:34:47 +0200 Armin Novak (aecda5280) + + * Added plausibility checks for order input coordinates. + +2018-10-09 14:24:58 +0200 Armin Novak (766a66a7c) + + * Fixed stream get position. + +2018-10-09 14:24:39 +0200 Armin Novak (166bdf018) + + * Fixed return value of rpc_channel_tls_connect + +2018-10-09 14:19:05 +0200 Armin Novak (65bfb67f7) + + * Fixed rpc_client_write_call resource cleanup. + +2018-10-09 14:16:27 +0200 Armin Novak (8c92f3436) + + * Fixed argument name for ntlm_client_encrypt + +2018-10-08 12:56:09 +0200 Martin Fleisz (00af869cd) + + * Merge pull request #4889 from + akallabeth/shadow_server_audin_refactor + +2018-10-08 10:13:51 +0200 Martin Fleisz (ea5a0adfc) + + * Merge pull request #4913 from akallabeth/audin_opensles + +2018-10-08 08:39:27 +0200 akallabeth (fbf1404cc) + + * Merge pull request #4918 from byteboon/master + +2018-10-05 09:43:00 -0700 byteboon (1d99d2d5f) + + * Regression: added back kerberos signature fix that was lost in a + recent refactor #4801 + +2018-10-05 11:00:13 +0200 akallabeth (9cc4f844c) + + * Merge pull request #4912 from akallabeth/swresample + +2018-10-05 09:50:27 +0200 Martin Fleisz (168bab905) + + * Merge pull request #4916 from Devolutions/ios-path-fix + +2018-10-05 09:05:57 +0200 akallabeth (da133fdff) + + * Merge pull request #4917 from Devolutions/array-list-equals-fix + +2017-07-21 15:57:34 -0400 Sébastien Duquette (2497fcf94) + + * Use fnObjectEquals in ArrayList_Remove. + +2017-10-06 14:55:34 -0700 Richard Markiewicz (ee7b5460b) + + * freerdp - fix iOS directory paths + +2017-02-15 14:50:24 -0500 Marc-André Moreau (1b42e512e) + + * winpr: add WINPR_DLL definition + +2018-10-04 13:53:18 +0200 Armin Novak (ac1476356) + + * [audin] Abort version exchange if server version is not supported. + +2018-10-04 12:21:28 +0200 Armin Novak (47f880407) + + * Fixed audio recording with opensles. + +2018-10-04 09:42:31 +0200 Bernhard Miklautz (8871d5558) + + * Merge pull request #4910 from akallabeth/warning_fixes + +2018-10-04 08:57:54 +0200 Armin Novak (fbe95209e) + + * Readded AVRESAMPLE support as fallback. + +2018-10-04 09:56:20 +0800 Vladimir Lomov (41cc2b63c) + + * Move from libavresample to libswresample + +2018-10-03 15:16:59 +0200 Armin Novak (a8a6accc1) + + * Fixed compiler warnings. + +2018-10-03 09:42:16 +0200 David Fort (2e1bf90bd) + + * Merge pull request #4885 from + akallabeth/autoreconnect_handle_window_events + +2018-10-02 15:46:17 +0200 akallabeth (4e71af677) + + * Merge pull request #4906 from FeLvi-zzz/japanese-patch + +2018-10-02 21:53:55 +0900 FeLvi_zzz (751cfde86) + + * remove untranslatable strings in Japanese translation + +2018-10-02 21:47:08 +0900 FeLvi_zzz (6d36707ec) + + * fixed typo in Japanese translation + +2018-10-02 12:33:52 +0200 Armin Novak (00489ae75) + + * Reworked checks in xf_disp.c + +2018-10-02 18:36:58 +0900 FeLvi_zzz (2564a6a2d) + + * modified Japanese translation #4905 + +2018-10-02 18:00:29 +0900 FeLvi_zzz (7a44e179c) + + * added Japanese translation + +2018-10-02 10:28:28 +0200 Armin Novak (3b7f522eb) + + * Release stream in transport_write in all error cases. + +2018-10-02 10:04:21 +0200 Bernhard Miklautz (57623d844) + + * Merge pull request #4901 from + akallabeth/cmd_line_flag_no_value_check + +2018-10-01 14:45:45 +0200 Martin Fleisz (6554bc3b8) + + * Merge pull request #4904 from akallabeth/floatbar_x11_leak + +2018-10-01 10:49:30 +0200 Armin Novak (f33277998) + + * Fixed floatbar X11 leak. + +2018-10-01 10:49:30 +0200 Armin Novak (046d2296a) + + * Fixed floatbar X11 leak. + +2018-09-28 12:59:20 +0200 Armin Novak (a0f42280c) + + * Check if a boolean or flag argument has additional data. Treat it + as an error. + +2018-09-28 12:29:29 +0200 Armin Novak (fc9ff6d2f) + + * Made gateway NTLM self contained. + +2018-09-28 12:08:27 +0200 Armin Novak (99eb9f7ec) + + * Refactored and simplified RPC signature functions. + +2018-09-28 08:43:43 +0200 Armin Novak (9516c251c) + + * Made TSG struct opaque + +2018-09-27 16:42:27 +0200 Armin Novak (7ab1251a6) + + * Refactored rpc_client and resolve gateway only once. + +2018-09-27 16:23:01 +0200 Armin Novak (f5f155b05) + + * Refactored RpcClient functions + +2018-09-27 16:08:28 +0200 Armin Novak (47ba37fbc) + + * Unified dns resolving of host + +2018-09-27 16:05:14 +0200 Armin Novak (8a677d6cf) + + * Refactored rdg channel structs. + +2018-09-27 15:19:41 +0200 Armin Novak (d748adbf1) + + * Refactored gateway ncacn HTTP to be self contained. + +2018-09-27 15:04:41 +0200 Armin Novak (a5fdf9e00) + + * Refactored gateway HTTP to be self contained. + +2018-09-25 17:13:25 +0200 Armin Novak (7e1589a3e) + + * Added default rdpsnd formats. + +2018-09-25 17:09:45 +0200 Armin Novak (c60ab7d06) + + * fixed stuff + +2018-09-25 17:05:12 +0200 Armin Novak (2cf066255) + + * Unified format support for rdpsnd. + +2018-09-25 16:52:27 +0200 Armin Novak (26ef8c9b3) + + * Added export define. + +2018-09-25 16:45:08 +0200 Armin Novak (40dae15cf) + + * Moved server-common to public header. + +2018-09-25 16:32:37 +0200 Armin Novak (d56efaae8) + + * Fixed server format selection. + +2018-09-25 16:25:35 +0200 Armin Novak (16531e143) + + * Fixed server audin callback, provide more information. + +2018-09-25 16:00:30 +0200 Armin Novak (5aa4b702c) + + * Fixed dst_format + +2018-09-25 15:56:05 +0200 Armin Novak (12f1cf9e3) + + * Fixed default format. + +2018-09-25 15:53:35 +0200 Armin Novak (a83c805ad) + + * Fixed format debug message. + +2018-09-25 15:53:10 +0200 Armin Novak (0560832b5) + + * Using common audio formats for input. + +2018-09-25 15:50:48 +0200 Armin Novak (db2a0dbdc) + + * Unified format selection. + +2018-09-25 15:46:36 +0200 Armin Novak (5e14bb1b1) + + * Mac fixes + +2018-09-25 15:18:37 +0200 Armin Novak (e61219eb5) + + * Fixed mac callbacks. + +2018-09-25 15:17:19 +0200 Armin Novak (d513f184e) + + * Fixed shadow server callbacks. + +2018-09-25 14:56:25 +0200 Armin Novak (18f97d03e) + + * Cleaned up defaults. + +2018-09-25 14:34:14 +0200 Armin Novak (106dde957) + + * Working mic redirection for shadow server. + +2018-09-25 12:04:10 +0200 Armin Novak (28efbbc01) + + * Refactored audio_format* functions. + +2018-09-26 11:27:57 +0200 Armin Novak (a5b689b35) + + * Readded override redirect but reset on focus loss. + +2018-09-26 11:13:06 +0200 Armin Novak (316eed1fb) + + * Menus are no longer popup windows but dropdown menus. + +2018-09-26 10:11:52 +0200 Armin Novak (fa7902c36) + + * Fixed argument check for floatbar events. + +2018-09-26 10:02:49 +0200 David Fort (d0612151f) + + * Merge pull request #4874 from r-barnett/fix-MonitorLocalShift + +2018-09-26 09:37:41 +0200 Martin Fleisz (a90b74b8d) + + * Merge pull request #4879 from akallabeth/clip_fix + +2018-09-26 09:37:23 +0200 Martin Fleisz (c3ec6d293) + + * Merge pull request #4862 from akallabeth/printer_warning_fix + +2018-09-26 09:20:54 +0200 Martin Fleisz (5339efd6e) + + * Merge pull request #4882 from akallabeth/no_proxy_cidr + +2018-09-25 16:34:20 +0200 akallabeth (0b8a66188) + + * Merge pull request #4865 from mmattes/feature/floatbar + +2018-09-25 14:38:09 +0200 Martin Fleisz (1d64a2464) + + * Merge pull request #4888 from akallabeth/shadow_server_audin + +2018-09-25 11:13:32 +0200 Armin Novak (dab5770fe) + + * Added microphone support to shadow server. + +2018-09-25 10:58:53 +0200 David Fort (443831bfe) + + * Merge pull request #4887 from akallabeth/rail_string_allow_empty + +2018-09-25 09:54:47 +0200 Armin Novak (93846c801) + + * Allow empty rail strings. + +2018-09-24 16:44:25 +0200 Armin Novak (8357f6181) + + * Fixed load/unload for display channel. + +2018-09-24 16:24:32 +0200 Armin Novak (51f97f2d3) + + * Fixed #3423: Process xevents when in reconnect mode. + +2018-09-24 16:00:27 +0200 David Fort (ba69925b8) + + * Merge pull request #4501 from akallabeth/drive_file_size_fix + +2018-09-24 14:09:10 +0200 David Fort (bfbcddf6a) + + * Merge pull request #4880 from akallabeth/auto_reconnect_unify + +2018-09-24 09:53:28 +0200 Armin Novak (13478c744) + + * Skip empty server format response. + +2018-09-24 09:38:01 +0200 Armin Novak (1d77875a6) + + * Fix NULL function pointer BeginPaint + +2018-09-24 09:08:50 +0200 Armin Novak (a5f0fa818) + + * Fixed freerdp_keyboard_layouts_free + +2018-09-24 09:07:59 +0200 Armin Novak (228e63d61) + + * Free RDP_KEYBOARD_LAYOUT with freerdp_keyboard_layouts_free + +2018-09-24 12:24:15 +0200 Armin Novak (941213f50) + + * Fixed domain and regex match. + +2018-09-24 11:42:23 +0200 Armin Novak (3a2bfa183) + + * Fixed #4878: Added cidr support for proxy exception check. + +2018-09-24 10:30:59 +0200 Armin Novak (897c0c72a) + + * Unified auto_reconnect functions for all clients. + +2018-09-24 09:46:33 +0200 David Fort (040d14b67) + + * Merge pull request #4869 from akallabeth/clear_fix + +2018-09-21 13:40:48 -0500 rbarnett (41664572a) + + * MonitorLocalShiftX,Y should be set when 1st monitor from MonitorIds + selected as primary + +2018-09-21 13:02:39 +0200 Martin Fleisz (2096c1108) + + * Merge pull request #4872 from akallabeth/sw_gdi_default + +2018-09-21 13:01:58 +0200 Martin Fleisz (205c61282) + + * Merge pull request #4871 from akallabeth/drdynvc_checks + +2018-09-20 13:14:24 +0200 Martin Fleisz (44b82a45b) + + * Merge pull request #4873 from akallabeth/leak_fix + +2018-09-20 12:07:36 +0200 akallabeth (30601608e) + + * Merge pull request #4855 from r-barnett/fix-logoff-exit-code + +2018-09-20 11:04:20 +0200 Armin Novak (bdff1c96f) + + * Fixed use after free and leak. + +2018-09-20 10:44:03 +0200 Armin Novak (dfb104965) + + * Fix #4851: Software GDI is now default + +2018-09-20 09:06:01 +0200 Armin Novak (baee520e3) + + * Fix for #4866: Added additional length checks + +2018-09-19 09:36:39 -0500 rbarnett (5d3e76bd8) + + * Replace cryptic names; move the disconnect ultimatum reasons enum + into public API and rename; remove setter + +2018-09-19 16:20:32 +0200 Martin Fleisz (92676fe15) + + * Merge pull request #4870 from corux/patch-1 + +2018-09-19 15:36:24 +0200 Tobias (a4df4f7bb) + + * Do not prompt if blank password was provided + +2018-09-19 14:10:50 +0200 Armin Novak (7e8d128fc) + + * Fixed clear codec reset and test cases. + +2018-09-19 13:02:29 +0200 Armin Novak (712a39898) + + * Fixed buffer size for clear_decompress test. + +2018-09-19 12:03:07 +0200 Armin Novak (13e59b5d6) + + * Fix #4868: Allow empty bands data. + +2018-09-19 13:45:15 +0200 Martin Fleisz (59ae00baa) + + * Merge pull request #4867 from akallabeth/empty_smartcard_filter_fix + +2018-09-19 11:13:02 +0200 Armin Novak (f63286dbe) + + * Fixed smartcard filter for empty arguments. + +2018-09-18 15:31:10 -0500 rbarnett (845826618) + + * Store the disconnect provider ulimatum reason in a new field in + struct rdp_context and move the test for a logoff reason + to xf_client.c + +2018-09-18 21:46:02 +0200 Markus Mattes (36fc5dde2) + + * fix hidden floatbar consumes a lot of cpu + +2018-09-18 21:25:51 +0200 Markus Mattes (21e4804a7) + + * implemented floatbar for x11 + +2018-09-18 14:45:25 +0200 Armin Novak (a74437811) + + * Fixed a warning in printer channel. + +2018-09-18 10:59:15 +0200 Martin Fleisz (24936c185) + + * Merge pull request #4859 from akallabeth/autoreconnect_gfx_fix + +2018-09-18 09:51:50 +0200 Armin Novak (4c491b5a1) + + * Fixed #4857: Properly reset clear codec. + +2018-09-17 09:08:47 +0200 Martin Fleisz (0b7b9c0dc) + + * Merge pull request #4842 from akallabeth/smartcard_rdp_logon + +2018-09-17 09:08:32 +0200 Martin Fleisz (5686a0f90) + + * Merge pull request #4840 from akallabeth/smartcard_filter + +2018-09-14 09:54:35 -0500 rbarnett (5db0b57fc) + + * Map a particular disconnect situation triggered by a user logging + off to a user logoff code. + +2018-09-14 10:59:31 +0200 Martin Fleisz (3c158299a) + + * Merge pull request #4853 from r-barnett/add-nego-fail-exit-code + +2018-09-14 10:58:36 +0200 Martin Fleisz (f7ee02372) + + * Merge pull request #4854 from akallabeth/rail_exec_arguments_fix + +2018-09-14 10:08:38 +0200 Armin Novak (bfeac80ed) + + * Fixed macro _stream_read_n16_le and _stream_read_n16_be + +2018-09-14 10:07:22 +0200 Armin Novak (97c909107) + + * Fixed const correctness for RAIL callbacks. + +2018-09-14 10:04:16 +0200 Armin Novak (5819946b8) + + * Fixed rail unicode string conversion and const correctness. + +2018-09-13 10:29:23 -0500 rbarnett (1e7be9908) + + * Add an exit code for a security protocol negotiation failure + +2018-09-13 09:57:16 +0200 akallabeth (56d001ef1) + + * Merge pull request #4852 from + r-barnett/fix-net-disconnect-exit-code + +2018-09-12 10:16:27 -0500 rbarnett (4e97edade) + + * Set an error exit code for an unsuccessful reconnect + +2018-09-12 11:35:08 +0200 Martin Fleisz (94143c323) + + * Merge pull request #4850 from r-barnett/fix-connection-type-parsing + +2018-09-11 10:17:52 -0500 rbarnett (e296a55fa) + + * Reject unknown connection type values for /network command line + option. + +2018-09-11 08:18:33 +0200 akallabeth (b0599afbb) + + * Merge pull request #4848 from mfleisz/longer_window_title + +2018-09-10 14:44:29 +0200 Martin Fleisz (e00dd1974) + + * wfreerdp: Increase buffer size for window title (#4731) + +2018-09-10 10:48:48 +0200 Martin Fleisz (bf22ce5f5) + + * Merge pull request #4844 from akallabeth/avcodec_version_check_fix + +2018-09-07 10:54:33 +0200 Armin Novak (cbb4be412) + + * Removed manipulation of authentication modes. + +2018-09-05 14:19:57 +0200 Armin Novak (5bddbd1cf) + + * Fixed avcodec version test. + +2018-09-05 15:28:06 +0200 Armin Novak (cf319001f) + + * Fixed out of bound access. + +2018-09-04 15:49:21 +0200 Armin Novak (0de43c8b8) + + * Added /smartcard-logon option to set flag. (Stripped version of + #4837 by @informatimago) + +2018-09-04 15:22:06 +0200 Armin Novak (4596588e0) + + * Set freed pointer to NULL avoiding double free. + +2018-09-04 15:17:01 +0200 David Fort (c2e2eb910) + + * Merge pull request #4839 from akallabeth/optional_begin_paint + +2018-09-04 12:58:05 +0200 Armin Novak (b2ce309b2) + + * Added multi filter for smartcard. (based on #4837 by + @informatimago) + +2018-09-04 10:40:17 +0200 Armin Novak (54f3a388d) + + * Fixed #4835: BeginPaint callback now optional. + +2018-09-03 10:55:03 +0200 David Fort (874021911) + + * Merge pull request #4836 from akallabeth/strcpy_fix + +2018-09-03 08:48:33 +0200 Armin Novak (817f8e0d4) + + * Fixed an issue introduced with #4822 + +2018-08-30 10:25:02 +0200 David Fort (25e2ab1c0) + + * Merge pull request #4822 from akallabeth/remove_unchecked_strcpy + +2018-08-29 11:40:50 +0200 Martin Fleisz (057c6095f) + + * Merge pull request #4827 from akallabeth/fedora_build_fix + +2018-08-27 10:52:22 +0200 Armin Novak (5bc3993e3) + + * Fixed buffer size and function name + +2018-08-27 09:15:50 +0200 Armin Novak (456b95cbf) + + * Fixed size of command line value string. + +2018-08-24 13:49:19 +0200 Armin Novak (fad20be6e) + + * Fixed missing includes. + +2018-08-24 12:15:06 +0200 Armin Novak (00a5d06fc) + + * Fixed coverity memory leak. + +2018-08-24 10:39:48 +0200 Armin Novak (62c1696d4) + + * Removed use of unchecked sprintf + +2018-08-24 09:54:25 +0200 Armin Novak (114abad76) + + * Removed use of strcpy. + +2018-08-27 14:33:09 +0200 akallabeth (9e3b48e0f) + + * Merge pull request #4829 from + informatimago/smartcard-logon-rdp--x509-certificate-info-extraction + +2018-08-27 13:51:30 +0200 Pascal J. Bourguignon (63d00f6f8) + + * Corrected the compatibility function names: + crypto_cert_subject_alt_name and + crypto_cert_subject_alt_name_free. + +2018-08-27 12:10:08 +0200 David Fort (595cdf272) + + * Merge pull request #4828 from akallabeth/warning_fixes_2_0 + +2018-08-24 16:04:29 +0200 Pascal J. Bourguignon (53692ffc5) + + * Compute certificate_path from __FILE__ to adapt to changing + compilation and test environments. + +2018-08-24 15:20:03 +0200 Pascal J. Bourguignon (79d2294a2) + + * Put back deprecated function names crypto_cert_get_alt_names and + crypto_cert_alt_names_free for FREERDP_API compatibility. + +2018-08-24 15:05:50 +0200 Pascal J. Bourguignon (98b860266) + + * Use C comment syntax instead of C++; added static declaration for + local functions. + +2018-08-24 14:03:04 +0200 Pascal J. Bourguignon (469f9bf48) + + * Smartcard Logon: restructured x509 certificate info extraction; + added extracting the UPN. + +2018-08-23 13:25:46 +0200 Armin Novak (5b0b18ae7) + + * Device name now const. + +2018-08-23 13:16:13 +0200 Armin Novak (33be80cb4) + + * Removed unused variables. + +2018-08-23 13:15:46 +0200 Armin Novak (6d3beabd5) + + * Removed unused variables in tests. + +2018-08-23 13:08:52 +0200 Armin Novak (d7d556789) + + * Fixed missing const. + +2018-08-23 13:08:31 +0200 Armin Novak (dab842cfb) + + * Fixed missing type casts. + +2018-08-23 13:06:34 +0200 Armin Novak (a3819f65e) + + * Fixed unused variable warnings. + +2018-08-23 13:06:15 +0200 Armin Novak (59819818f) + + * Fixed freerdp_load_dynamic_addin path + +2018-08-23 13:05:44 +0200 Armin Novak (8d473af4f) + + * Fixed missing type cast. + +2018-08-23 13:05:12 +0200 Armin Novak (d90e5da86) + + * Fixed unused label warning. + +2018-08-23 13:04:42 +0200 Armin Novak (bff49a9bd) + + * Fixed invalid argument warnings. + +2018-08-23 12:45:36 +0200 Armin Novak (48125164d) + + * Fixed dead initialization. + +2018-08-23 12:43:29 +0200 Armin Novak (c159b2e9c) + + * Fixed missing check before calling memcpy + +2018-08-24 13:21:27 +0200 Armin Novak (afbc96929) + + * Fixed wayland man page detection on fedora/redhat builds. + +2018-08-24 11:41:58 +0200 Martin Fleisz (0fb19d04b) + + * Merge pull request #4810 from akallabeth/no_proxy_support + +2018-08-24 09:48:51 +0200 Martin Fleisz (f9e52c185) + + * Merge pull request #4815 from akallabeth/async_transport_remove + +2018-08-24 09:45:26 +0200 Martin Fleisz (8248dcb3b) + + * Merge pull request #4816 from akallabeth/drive_cmd_fix + +2018-08-24 08:37:41 +0200 Martin Fleisz (0afba5840) + + * Merge pull request #4814 from akallabeth/linked_list_add_object + +2018-08-21 11:01:54 +0200 Armin Novak (b5df39756) + + * Added option to ignore proxy env. + +2018-08-21 10:57:44 +0200 Armin Novak (a0facc329) + + * Added option to deactivate proxy. + +2018-08-21 10:53:33 +0200 Armin Novak (4bea9934c) + + * Added patch from #4697 + +2018-08-23 16:58:22 +0200 Martin Fleisz (ebef5a5e2) + + * Merge pull request #4811 from akallabeth/dyn_fullscreen_fix + +2018-08-23 16:07:48 +0200 Martin Fleisz (3381ca46e) + + * Merge pull request #4787 from akallabeth/redirect_fqdn_fix + +2018-08-23 10:04:26 +0200 Armin Novak (ab18f8f22) + + * Fix #4680: Return proper directory name. + +2018-08-23 09:40:49 +0200 David Fort (7b53ae618) + + * Merge pull request #4813 from ondrejholy/coverity + +2018-08-20 11:11:47 +0200 Ondrej Holy (95a043e0e) + + * winpr/winsock: Fix leak found by covscan + +2018-08-22 13:17:10 +0200 Ondrej Holy (0a11a06dc) + + * winpr/winsock: Format code by astyle + +2018-08-21 10:27:56 +0200 Ondrej Holy (10b9c516f) + + * winpr/utils/wlog: Fix leak found by covscan + +2018-08-22 13:16:58 +0200 Ondrej Holy (d3c2ceb0f) + + * winpr/utils/wlog: Format code by astyle + +2018-08-20 10:55:29 +0200 Ondrej Holy (4813a7089) + + * winpr/utils/ntlm: Prevent releasing function argument + +2018-08-22 17:53:16 +0200 David Fort (d093189ac) + + * Merge pull request #4797 from akallabeth/rpm_expand_fix + +2018-08-22 13:16:31 +0200 Ondrej Holy (1c1d00aac) + + * winpr/utils/ntlm: Format code by astyle + +2018-08-20 09:52:24 +0200 Ondrej Holy (35bccd526) + + * winpr/sspi/ntlm: Fix leak found by covscan + +2018-08-20 09:50:43 +0200 Ondrej Holy (724bc7acd) + + * winpr/io/device: Fix leak found by covscan + +2018-08-22 13:16:03 +0200 Ondrej Holy (df9d0fab8) + + * winpr/io/device: Format code by astyle + +2018-08-20 09:47:33 +0200 Ondrej Holy (acbd6e632) + + * winpr/file: Fix leak found by covscan + +2018-08-20 09:33:42 +0200 Ondrej Holy (24eb53e20) + + * uwac: Fix leak found by covscan + +2018-08-22 13:15:32 +0200 Ondrej Holy (91c398dc9) + + * uwac: Format code by astyle + +2018-08-20 09:10:49 +0200 Ondrej Holy (3a5fdd0a3) + + * rdtk: Fix leak found by covscan + +2018-08-21 10:12:05 +0200 Ondrej Holy (0b7d0c200) + + * crypto/tls: Prevent usage of freed pointer found by coverity + +2018-08-20 11:26:35 +0200 Ondrej Holy (47595a857) + + * core/transport: Fix leak found by covscan + +2018-08-17 16:25:20 +0200 Ondrej Holy (1a413b5b4) + + * core/tcp: Prevent buffer overflow found by covscan + +2018-08-22 13:15:10 +0200 Ondrej Holy (26bc52f79) + + * core/tcp: Format code by astyle + +2018-08-17 16:22:56 +0200 Ondrej Holy (7e4fa6702) + + * core/proxy: Fix leak found by covscan + +2018-08-17 16:20:43 +0200 Ondrej Holy (2417a6a16) + + * core/nla: Fix leak found by covscan + +2018-08-17 16:16:37 +0200 Ondrej Holy (6e0f05cbd) + + * core/nego: Fix leak found by covscan + +2018-08-17 16:14:53 +0200 Ondrej Holy (8f8d91e36) + + * core/listener: Prevent buffer overflow found by covscan + +2018-08-21 09:45:46 +0200 Ondrej Holy (23c3c188c) + + * core/info: Silence false positive warnings from covscan + +2018-08-17 16:10:26 +0200 Ondrej Holy (4a7bb1842) + + * core/info: Fix leak found by covscan + +2018-08-17 16:00:19 +0200 Ondrej Holy (83e966d9e) + + * core/gateway/rpc: Fix leak found by covscan + +2018-08-22 13:14:45 +0200 Ondrej Holy (6de583e13) + + * core/gateway/rpc: Format code by astyle + +2018-08-17 15:47:46 +0200 Ondrej Holy (409e19233) + + * core/gateway/rdg: Fix leak found by covscan + +2018-08-21 09:16:47 +0200 Ondrej Holy (79d0725a8) + + * codec/planar: Fix leak found by covscan + +2018-08-22 13:40:41 +0200 Armin Novak (c3a26b0d6) + + * Removed +async-transport options + +2018-08-17 15:01:25 +0200 Ondrej Holy (36960e97a) + + * codec/nsc: Fix leak found by covscan + +2018-08-17 14:56:49 +0200 Ondrej Holy (99c15e533) + + * cache: Fix wrong condition found by covscan + +2018-08-17 14:45:07 +0200 Ondrej Holy (f36054b37) + + * client/cmdline: Fix leak found by covscan + +2018-08-17 14:40:12 +0200 Ondrej Holy (e9549a3bd) + + * client/common: Fix leak found by covscan + +2018-08-21 09:07:15 +0200 Ondrej Holy (e7d5aae51) + + * client/x11: Silence false positive warnings from covscan + +2018-08-17 14:28:55 +0200 Ondrej Holy (baeb29a7e) + + * client/x11: Fix leak found by covscan + +2018-08-22 13:13:37 +0200 Ondrej Holy (dde4c3838) + + * client/x11: Format code by astyle + +2018-08-17 14:19:19 +0200 Ondrej Holy (97f25e8ab) + + * channels/smartcard: Fix leak found by covscan + +2018-08-22 13:13:07 +0200 Ondrej Holy (3baa71670) + + * channels/smartcard: Format code by astyle + +2018-08-21 09:11:19 +0200 Ondrej Holy (ab7ab7a7c) + + * channels/server: Silence false positive warnings from covscan + +2018-08-22 13:12:35 +0200 Ondrej Holy (4ba3c46cd) + + * channels/server: Format code by astyle + +2018-08-17 13:55:56 +0200 Ondrej Holy (170d5859d) + + * channels/serial: Fix leak found by covscan + +2018-08-17 13:52:38 +0200 Ondrej Holy (d3ab04d78) + + * channels/remdesk: Fix leak found by covscan + +2018-08-17 13:47:24 +0200 Ondrej Holy (405c13338) + + * channels/rdpgfx: Fix leak found by covscan + +2018-08-22 13:11:28 +0200 Ondrej Holy (36a68b4ea) + + * channels/rdpgfx: Format code by astyle + +2018-08-17 13:43:18 +0200 Ondrej Holy (1001807c5) + + * channels/rdpdr: Prevent buffer overflow found by covscan + +2018-08-22 13:07:46 +0200 Ondrej Holy (472576e6e) + + * channels/rdpdr: Format code by astyle + +2018-08-17 12:56:45 +0200 Ondrej Holy (10bddb9fd) + + * channels/rdpdr: Fix leak found by covscan + +2018-08-17 12:51:19 +0200 Ondrej Holy (865ee84ab) + + * channels/rail: Fix leak found by covscan + +2018-08-17 12:43:49 +0200 Ondrej Holy (4b8f2d513) + + * channels/drive: Fix leak found by covscan + +2018-08-17 12:41:34 +0200 Ondrej Holy (7b740f152) + + * channels/addin: Fix leak found by covscan + +2018-08-17 12:30:33 +0200 Ondrej Holy (926ac4f93) + + * channels/audin: Fix leak found by covscan + +2018-08-22 12:33:34 +0200 Armin Novak (b77dc13b5) + + * Implemented linked list compare and value copy functions. + +2018-08-21 12:58:55 +0200 Armin Novak (02dc6ab3f) + + * Fixed single monitor fullscreen resolution update. + +2018-08-21 10:01:47 +0200 Martin Fleisz (560552ce1) + + * Merge pull request #4808 from akallabeth/tls_extract_pem_fix + +2018-08-21 09:08:33 +0200 Armin Novak (026ff00e7) + + * Fixed #4806 broken bounds check. + +2018-08-13 15:44:53 +0200 Armin Novak (210939988) + + * Removed comments with variables and (previously added) buggy suse + conditionals + +2018-08-13 15:21:49 +0200 David Fort (735ab2e8b) + + * Merge pull request #4795 from akallabeth/rpm_build_fix + +2018-07-10 20:22:18 +0200 Andreas Gröger (525d089fa) + + * Update X11-modifier key state on focus_in + +2018-08-13 14:34:06 +0200 Armin Novak (aad5c45b6) + + * Deactivated FFMPEG support for redhat systems (deps not in repo) + +2018-08-13 14:33:49 +0200 Norbert Federa (2353287e0) + + * Merge pull request #4794 from akallabeth/drive_find_first_file_fix + +2018-08-13 13:23:52 +0200 Armin Novak (dbd630a38) + + * drive_file_query_information: Use GetFileAttributesExW + +2018-08-13 13:17:56 +0200 Armin Novak (8b8e85271) + + * Fixed #4793: Return correct file handle for existing directory + +2018-08-09 10:41:56 +0200 akallabeth (dd26659ab) + + * Merge pull request #4789 from akallabeth/nightly_ffmpeg_rpm + +2018-08-09 10:22:24 +0200 David Fort (fd1c94bfb) + + * Merge pull request #4788 from akallabeth/multimon_fullscreen + +2018-08-09 09:58:56 +0200 Armin Novak (2b5b7cb3c) + + * Added requirement check for WITH_DSP_FFMPEG + +2018-08-08 13:31:52 +0200 Armin Novak (f78794b72) + + * Enabled ffmpeg support on RPM based systems. + +2018-08-08 13:10:07 +0200 akallabeth (b18f9ee86) + + * Merge pull request #4783 from akallabeth/nightly_audio + +2018-08-08 13:04:26 +0200 Armin Novak (a334aa965) + + * Fixed #4786: Added fullscreen handling for dynamic resolution. + +2018-08-08 12:26:57 +0200 Armin Novak (13564dbb4) + + * Allow redirect address override with a list of values. + +2018-08-08 11:16:24 +0200 Armin Novak (cc5e402cd) + + * Added command line option /redirect-prefer: + +2018-08-08 10:25:09 +0200 Armin Novak (f6b6eba0a) + + * Try redirection FQDN first, but check if it is resolvable. + +2018-08-06 07:55:30 +0200 Armin Novak (98ddde0cc) + + * Enabled FFMPEG dependency. + +2018-08-01 15:59:34 +0200 akallabeth (92c2d83a4) + + * Merge pull request #4778 from akallabeth/2_0_0_dev_4 + +2018-08-01 12:33:34 +0200 Armin Novak (97e7eca30) + + * Started next development cycle + +2018-08-01 15:27:31 +0200 akallabeth (a4f147683) + + * Merge pull request #4777 from akallabeth/changelog_2_0_0-rc3 + +2018-08-01 15:16:07 +0200 Martin Fleisz (1c75854a3) + + * Merge pull request #4776 from akallabeth/fixes_cleanups_etc + +2018-08-01 11:58:24 +0200 Armin Novak (ec0a0fef2) + + * Added const to function buffer pointers + +2018-08-01 11:57:18 +0200 Armin Novak (2a3a66b18) + + * Fixed expression ambiguity + +2018-08-01 11:56:47 +0200 Armin Novak (98c254ffa) + + * Fixed invalid return value type. + +2018-08-01 11:56:04 +0200 Armin Novak (eed5a41b6) + + * Fixed funtion to function pointer argument mismatch + +2018-08-01 11:54:45 +0200 Armin Novak (0352dc3d6) + + * Fixed invalid format string. + +2018-08-01 11:54:18 +0200 Armin Novak (cc44119dc) + + * Fixed missing array initializer values + +2018-08-01 11:44:45 +0200 Armin Novak (44d1438ea) + + * Fixed mac audin + +2018-08-01 10:04:00 +0200 Armin Novak (31f933bc1) + + * Fixed mac server compile issue. + +2018-07-31 11:29:59 +0200 Armin Novak (619ce84cd) + + * release: version 2.0.0-rc3 + +2018-07-31 13:35:05 +0200 MartinHaimberger (30626a5dc) + + * Merge pull request #4773 from akallabeth/drive_multi_fix + +2018-07-31 11:13:29 +0200 Martin Fleisz (70b3e442e) + + * Merge pull request #4774 from akallabeth/audin_leak_fix + +2018-07-31 11:03:39 +0200 Martin Fleisz (e3eae5db8) + + * Merge pull request #4240 from akallabeth/wl_client_fixes + +2018-07-31 10:45:04 +0200 Armin Novak (3a30844db) + + * Added default return value. + +2018-07-31 10:33:19 +0200 Armin Novak (7355b4e5f) + + * Fixed leak in audio format processing. + +2018-07-31 10:22:22 +0200 MartinHaimberger (2d7499b7c) + + * Merge pull request #4758 from akallabeth/dsp_fix + +2018-07-30 13:31:32 +0200 akallabeth (88474af92) + + * Merge pull request #4762 from mmattes/issue/4757 + +2018-07-30 13:16:45 +0200 Armin Novak (adc0882f8) + + * Removed obsolete winodws path hack. + +2018-07-30 12:58:15 +0200 Armin Novak (93fa8eb0d) + + * Fixed windows automount drive arguments. + +2018-07-30 12:37:19 +0200 Armin Novak (4035ed46c) + + * Added automount flag for windows and macos implementations. + +2018-07-30 12:31:11 +0200 Armin Novak (e8393a22e) + + * Remember if drive was added by automout. + +2018-07-30 12:29:18 +0200 Martin Fleisz (da8e58760) + + * Merge pull request #4741 from akallabeth/find_file_fix + +2018-07-30 12:28:38 +0200 Martin Fleisz (143a2b149) + + * Merge pull request #4755 from akallabeth/dyn_resize_fix + +2018-07-30 11:22:11 +0200 Armin Novak (033abe93d) + + * Fixed callback parameter checks. + +2018-07-30 10:47:34 +0200 akallabeth (ffd84916f) + + * Merge pull request #4765 from mmattes/fix/double-import-xinput2 + +2018-07-30 10:46:20 +0200 Armin Novak (ed8932834) + + * Fixed missing argument checks. + +2018-07-30 10:37:50 +0200 akallabeth (6b07a3f2b) + + * Merge pull request #4772 from Mandar-Shinde/master + +2018-07-27 15:54:57 +0530 Mandar (093fe8338) + + * macos: Bring RDP window to front + +2018-07-24 14:03:45 +0200 Markus Mattes (e6209748f) + + * Removed double ifdef WITH_XI, XInput2.h already included + +2018-07-23 22:06:09 +0200 David Fort (6bd1a7d2a) + + * Merge pull request #4759 from mfleisz/audin_srv_fix + +2018-07-22 20:00:25 +0200 Markus Mattes (bad8bbadf) + + * Fix for #4757 + +2018-07-19 16:21:03 +0200 Armin Novak (3b187ef32) + + * Code Cleanup + +2018-07-19 15:54:40 +0200 Martin Fleisz (b6a41b26e) + + * audin: Fix server-side dsp decoding + +2018-07-19 15:38:44 +0200 Armin Novak (a984dd7f5) + + * Updated experimental list. + +2018-07-19 15:17:54 +0200 Armin Novak (d40daedb9) + + * Fixed FFMPEG backend: Do not drop samples for package alignment. + +2018-07-19 12:20:14 +0200 Armin Novak (c192c17c8) + + * Fixed mixed declaration. + +2018-07-19 11:53:36 +0200 Armin Novak (d7e88b1b8) + + * Fixed winmm backend logging. + +2018-07-19 11:46:54 +0200 Armin Novak (a003890b3) + + * Fixed opensles compilation errors. + +2018-07-18 16:32:53 +0200 Martin Fleisz (5a154dccb) + + * Merge pull request #4754 from + akallabeth/expose_cert_redirection_flag + +2018-07-16 17:08:26 +0200 Armin Novak (3d6c41746) + + * Expose redirection flag for certificate. + +2018-07-18 15:16:50 +0200 Armin Novak (328eba7fe) + + * Fix #4752: Provide message free function for channel queue. + +2018-07-18 14:29:22 +0200 Armin Novak (4e4ec0b03) + + * Fix #4752: Unsubscirbe all PubSub in dynamic channel. + +2018-07-18 12:33:52 +0200 Armin Novak (ec83f3d4f) + + * Fixed number of samples returned. + +2018-07-18 12:33:39 +0200 Armin Novak (00b073add) + + * Fixed DVI_ADPCM mapping. + +2018-07-18 12:14:37 +0200 Armin Novak (7c8a55637) + + * Fixed alignment issues. + +2018-07-18 09:31:04 +0200 Armin Novak (ced4d06f7) + + * Fixed #4679, #4753 dynamic resizing + +2018-07-17 14:55:19 +0200 Armin Novak (8664a3c91) + + * Fixed alsa and pulse backend receive buffer sizes + +2018-07-17 12:57:57 +0200 Armin Novak (6029a411e) + + * Fixed ima_adpcm encoder bug. + +2018-07-17 10:57:08 +0200 Armin Novak (b9645c924) + + * Using dynamic logger again. + +2018-07-17 10:30:35 +0200 Armin Novak (7260a4fd8) + + * Fixed override of stream data in dsp_encode methods. + +2018-07-13 13:54:03 +0200 Martin Fleisz (7705535f9) + + * Merge pull request #4745 from akallabeth/redirect_fix_follow_up + +2018-07-13 13:11:38 +0200 Armin Novak (7a6b8a04b) + + * Fixed channel reconnect after redirect. + +2018-07-11 16:37:29 +0200 Armin Novak (3d8dec7fb) + + * Removed debug log messages. + +2018-07-11 16:27:14 +0200 Armin Novak (dbfa896d5) + + * Fixed errno reset. + +2018-07-11 15:41:05 +0200 Martin Fleisz (4d0876fcc) + + * Merge pull request #4742 from mfleisz/fix_wave2 + +2018-07-11 15:06:31 +0200 Martin Fleisz (0ec957901) + + * rdpsnd: Fix sending of wave2 PDU + +2018-07-11 10:58:37 +0200 Armin Novak (2b91095eb) + + * Fixed pattern detection if path is already a directory. + +2018-07-11 10:53:26 +0200 Armin Novak (30843ef4d) + + * Code cleanups and more logging. + +2018-07-10 17:31:08 +0200 Martin Fleisz (fc925a7f2) + + * Merge pull request #4738 from akallabeth/connect_timeout_retry + +2018-07-10 14:57:13 +0200 Armin Novak (7ebc89951) + + * Fixed PEM certificate reading. + +2018-07-10 13:26:25 +0200 Armin Novak (f617d0d3c) + + * Moved automatic reconnect after timeout to freerdp_connect. + +2018-07-10 12:49:46 +0200 Armin Novak (8ba8a6244) + + * Added automatic reconnect if freerdp_connect fails due to timeout. + +2018-07-10 12:21:38 +0200 Armin Novak (77eb93b4b) + + * Made internal functions static to help compiler optimize. + +2018-07-10 12:04:27 +0200 Armin Novak (7a39dcd7e) + + * Updated reconnect to handle cases where PostConnect was not called + +2018-07-10 10:03:49 +0200 Armin Novak (c9cebf6ed) + + * Remember accepted PEM cert to avoid unnecessary user input. + +2018-07-09 17:45:50 +0200 Armin Novak (0d1895e4e) + + * Fixed async input return value check. + +2018-07-05 16:37:15 +0200 Martin Fleisz (e326f7144) + + * Merge pull request #4727 from akallabeth/new_error + +2018-07-05 15:20:52 +0200 Armin Novak (398da7340) + + * Added no or missing credentail error. + +2018-07-05 09:50:03 +0200 Martin Fleisz (fc84e6dd2) + + * Merge pull request #4726 from akallabeth/bitmap_cache_fix + +2018-07-05 08:44:42 +0200 Armin Novak (8f7dbe505) + + * Fix #4725: Need to copy data. + +2018-07-04 14:21:36 +0200 Martin Fleisz (a0fddd174) + + * Merge pull request #4530 from akallabeth/order_refactor + +2018-07-04 13:44:38 +0200 Armin Novak (de8be5d50) + + * Fixed indentation. + +2018-07-04 13:10:38 +0200 David Fort (a1d9399ca) + + * Merge pull request #4724 from akallabeth/wave2_server + +2018-07-04 11:03:32 +0200 Armin Novak (4465bcfa8) + + * Fixed remarks + +2018-07-04 10:50:41 +0200 David Fort (1107220ec) + + * Merge pull request #4645 from akallabeth/mac_ports_removed + +2018-07-03 16:07:05 +0200 Martin Fleisz (aaaee8015) + + * Merge pull request #4700 from informatimago/rdpsettings-script + +2018-07-03 14:35:57 +0200 Pascal J. Bourguignon (45841f8e6) + + * Applied autoformat.sh manually to settings.h + +2018-07-03 13:33:05 +0200 Pascal J. Bourguignon (35477c35d) + + * Use tabs to indent the comment in rdp_settings too. + +2018-07-03 12:45:15 +0200 Martin Fleisz (187cf000b) + + * Merge pull request #4706 from khvMX/master + +2018-07-03 09:54:29 +0200 Armin Novak (bf70ee626) + + * Keep extra data of audio format locally cached. + +2018-07-02 16:46:03 +0200 Armin Novak (a554207c1) + + * Added target dependencies. + +2018-07-02 16:38:21 +0200 Armin Novak (7cd25027a) + + * Fixed empty lib. + +2018-07-02 16:33:50 +0200 Armin Novak (73b8963d1) + + * Added automatic format support filter. + +2018-07-02 16:09:27 +0200 Armin Novak (30283e18e) + + * Fixed warning. + +2018-07-02 16:08:47 +0200 Armin Novak (373bfac9a) + + * Added support for WAVE2 PDU in server side audio channel. + +2018-06-26 10:19:41 +0200 Martin Fleisz (b34e3bcf7) + + * Merge pull request #4681 from akallabeth/wording_consistent + +2018-06-26 00:02:58 +0200 David Fort (eb1727bb8) + + * Merge pull request #4710 from akallabeth/reconnect_fixes + +2018-06-19 17:28:22 +0200 Armin Novak (35cd438ec) + + * Added enum for client connection state. + +2018-06-19 16:57:45 +0200 Armin Novak (9a47ce3f7) + + * Fixed missing variable type + +2018-06-19 16:48:05 +0200 David Fort (3ec0113df) + + * Merge pull request #4711 from + akallabeth/command_line_cleanup_rework + +2018-06-19 12:55:29 +0200 Armin Novak (348ecc4c8) + + * Fixed memory leak in command line value parsing. + +2018-06-19 12:55:29 +0200 Armin Novak (b9b30f92c) + + * Fixed memory leak in command line value parsing. + +2018-06-19 12:46:58 +0200 Armin Novak (e44d10a3e) + + * Merge remote-tracking branch 'origin/pr/4701' into reconnect_fixes + +2018-06-18 10:44:35 +0200 Armin Novak (273655a85) + + * Follow up fix for #4631 + +2018-06-18 10:23:57 +0200 Armin Novak (a716dc244) + + * Removed duplicate resource free. + +2018-06-08 11:35:02 +0200 Viktor Mukha (16cde2ee2) + + * X11: fixed Right-Ctrl ungrab feature (PR #3622) + +2018-06-07 13:29:44 +0200 Pascal J. Bourguignon (17a3782d1) + + * FIX: moved declarations above the statements for strict C 90 + compliance. + +2018-06-06 17:08:52 +0200 Pascal J. Bourguignon (a7c402255) + + * Corrected update-rdpSettings according to PR comments. Updated + settings.h with it. + +2018-06-06 16:43:09 +0200 Pascal J. Bourguignon (15f2bafea) + + * Cleaned up const char** -> char** for argv, since we definitely do + modify the argv! (we overwrite the password and pin + arguments). This implies changes in the argument parsing + tests that now must pass a mutable argv (copied from the + statically declared test argvs). Some other const + inconsistency have been dealt with too. + +2018-05-25 14:51:55 +0200 Pascal J. Bourguignon (25dafa381) + + * Created script to update the #define from rdp_settings fields. + +2018-05-23 10:27:39 +0200 Pascal J. Bourguignon (118ce7f12) + + * Aligned columns in rdpSettings structure declaration. + +2018-06-04 11:29:01 +0200 David Fort (dad6b7a53) + + * Merge pull request #4694 from akallabeth/mic_crash_fix + +2018-06-04 10:14:29 +0200 Armin Novak (2d69e369b) + + * Fixed #4693: Fix integer underflow in encoder loop. + +2018-05-30 12:39:17 +0200 Martin Fleisz (73588bc2b) + + * Merge pull request #4683 from akallabeth/ffmpeg_found_fix + +2018-05-30 12:13:24 +0200 Armin Novak (f8a1bb845) + + * Fixed case of variable names. + +2018-05-29 12:10:53 +0200 Martin Fleisz (fad23aab2) + + * Merge pull request #4677 from akallabeth/build_dep_fix + +2018-05-28 15:30:50 +0200 Armin Novak (4c0007b55) + + * Fix #4672: Check if FFMPEG and OpenH264 detected + +2018-05-22 16:22:10 +0200 Martin Fleisz (e90184cc5) + + * Merge pull request #4665 from FreeRDP/akallabeth-patch-1 + +2018-05-18 09:03:30 +0200 akallabeth (43dd47141) + + * Update issue templates + +2018-05-17 10:08:05 +0200 Armin Novak (8dba31ea0) + + * Fixed #4636: Consistent wording for boolean options depending on + default. + +2018-05-16 16:15:50 -0400 Mike Gilbert (9460f4292) + + * primitives: ensure primitives_get() returns a populated struct + +2018-05-16 09:53:30 +0200 David Fort (0255a7db1) + + * Merge pull request #4654 from akallabeth/alsa_latency_patch + +2018-05-16 08:45:17 +0200 Armin Novak (c078aee23) + + * Return real alsa latency if buffer is filled. + +2018-05-16 08:01:09 +0200 akallabeth (81c41c2a8) + + * Merge pull request #4653 from rjcorrig/kb4093753 + +2018-05-15 15:53:36 -0400 Robert Corrigan (992554a01) + + * Update time zone data to April 2018 + +2018-05-15 16:29:27 +0200 Martin Fleisz (1cb14010a) + + * Merge pull request #4651 from akallabeth/loadepng_memleak_fix + +2018-05-15 15:09:49 +0200 Martin Fleisz (278fef24a) + + * Merge pull request #4648 from akallabeth/nsc_free_fix + +2018-05-15 14:57:00 +0200 Armin Novak (0cf4dcc01) + + * Fix missing sound arrival time for wave2 PDU + +2018-05-15 14:30:04 +0200 Armin Novak (5a5b5eb6d) + + * Fixed loadepng memory leak. + +2018-05-15 13:47:28 +0200 Martin Fleisz (f65368695) + + * Merge pull request #4637 from akallabeth/win_ninja_support + +2018-05-15 13:46:57 +0200 Martin Fleisz (dd408318b) + + * Merge pull request #4631 from akallabeth/santizer_fixes + +2018-05-15 09:13:00 +0200 Armin Novak (ae765430e) + + * Fixed #4647: nsc_context_free must not access possibly + uninitialized fields. + +2018-05-14 15:04:34 +0200 David Fort (c5b84db7e) + + * Merge pull request #4638 from + akallabeth/known_hosts_comment_support + +2018-05-11 11:09:54 +0200 Armin Novak (9de99f15d) + + * Added comment support for known_hosts format. + +2018-05-14 10:39:12 +0200 Armin Novak (3c7dfa0a0) + + * Fix #2617: Removed MacPorts from CMake (default) search path. + +2018-05-11 11:00:46 +0200 Armin Novak (e8b911650) + + * Fixed invalid function argument for + ntlm_compute_message_integrity_check + +2018-05-11 11:00:01 +0200 Armin Novak (e71a39f21) + + * Fixed compiler warnings (unused) + +2018-05-06 11:17:08 +0200 Armin Novak (e1ea44127) + + * Fixed #4629: Only call freerdp_channels_post_connect when it was + connected. + +2018-05-11 10:37:50 +0200 Armin Novak (a18ee2e7b) + + * VS2017 support: set pdb output directory for Ninja generator. + +2018-05-06 10:49:05 +0200 Armin Novak (6e958e7ed) + + * Fix #4628: CommandLineFindNextArgumentA must check the current + argument + +2018-04-28 14:13:17 -0700 Andre Esteve (ab0bc2a7f) + + * X11: Fix fullscreen toggle + +2018-05-04 13:28:18 +0200 Martin Fleisz (7eb12bb02) + + * Merge pull request #4610 from akallabeth/cmd_strtol_fix + +2018-05-04 13:08:45 +0200 Martin Fleisz (c4e8685a2) + + * Merge pull request #4623 from akallabeth/mac_sound_backend_fix + +2018-05-04 13:07:01 +0200 Martin Fleisz (9c02f1bd1) + + * Merge pull request #4627 from akallabeth/clang_warning_fixes + +2018-05-04 12:03:26 +0200 Armin Novak (28ac0ee14) + + * Fixed NULL dereferences. + +2018-05-04 12:36:29 +0200 Armin Novak (87c19b30d) + + * Fixed uninitialized return and early resource cleanup. + +2018-05-04 12:36:18 +0200 Armin Novak (fb032f91b) + + * Fixed uninitialized value. + +2018-05-04 12:35:51 +0200 Armin Novak (46a62aa1a) + + * Fixed missing NULL pointer checks. + +2018-05-04 11:59:21 +0200 Martin Fleisz (65e329782) + + * Merge pull request #4624 from akallabeth/pth_fix + +2018-05-04 11:46:46 +0200 Armin Novak (069c58a72) + + * Fixed memory leak. + +2018-05-04 09:54:49 +0200 Armin Novak (458e51eae) + + * Do not set password to identity if pth is used. + +2018-05-04 10:06:42 +0200 Martin Fleisz (99346d19c) + + * Merge pull request #4611 from akallabeth/argument_warnings + +2018-05-04 10:04:37 +0200 akallabeth (0cf184d35) + + * Merge pull request #4625 from dualmoon/fix-hisher-pronouns + +2018-05-04 09:44:06 +0200 Armin Novak (670c1190c) + + * Fixed formats supported by backend. + +2018-05-04 09:10:31 +0200 Armin Novak (b59b0a442) + + * Added error log messages. + +2018-05-03 12:11:13 -0400 Ashley Davis (ae54f5bde) + + * First person "they" pronouns in logoff message + +2018-05-03 17:49:14 +0200 Armin Novak (5b961e9c7) + + * Fixed /pth: Consistently treat the hash offset to password length. + +2018-05-03 16:12:12 +0200 Armin Novak (17d43edaf) + + * Fixed mac sound backend initialization. + +2018-05-03 13:35:20 +0200 Martin Fleisz (1a27f28ba) + + * Merge pull request #4620 from akallabeth/bio_ctrl_fix + +2018-05-03 12:25:52 +0200 Armin Novak (d4c98e4e7) + + * Fixed formatting. + +2018-05-03 12:24:16 +0200 Armin Novak (5765e9a42) + + * Fixed #4476: broken casts/variable sizes for custom BIO calls. + +2018-05-03 11:56:58 +0200 David Fort (456b0e893) + + * Merge pull request #4453 from akallabeth/sound_channel_refactor + +2018-05-03 11:55:03 +0200 akallabeth (dd577377d) + + * Merge pull request #4617 from kevans91/spurious + +2018-05-03 11:31:54 +0200 akallabeth (d130d9cb2) + + * Merge pull request #4613 from kevans91/file64 + +2018-05-03 10:56:04 +0200 akallabeth (ba37f04e1) + + * Merge pull request #4616 from kevans91/timerfd-nonblock + +2018-05-03 10:23:12 +0200 Martin Fleisz (296b19e17) + + * Merge pull request #4596 from p-pautov/rdg_ssl_fixes + +2018-05-03 10:08:56 +0200 Armin Novak (066cb52ca) + + * Fixed treat_wave sample length and checks. + +2018-05-03 09:49:31 +0200 akallabeth (613e0be20) + + * Merge pull request #4614 from kevans91/cmakemod + +2018-05-03 08:55:23 +0200 akallabeth (94b316bf8) + + * Merge pull request #4618 from kevans91/buildtest + +2018-05-02 23:19:44 -0500 Kyle Evans (8073a7850) + + * Pull in the libepoll-shim includes for libwinpr's synch/test + +2018-05-02 10:57:16 -0500 Kyle Evans (2fb992a96) + + * Upstream the rest of our local FreeBSD patching + +2018-05-02 21:03:49 -0500 Kyle Evans (f1a7c3cc6) + + * Pass TFD_NONBLOCK to timerfd_create to avoid later fcntl + +2018-05-02 17:59:10 +0200 akallabeth (2215071b2) + + * Merge pull request #4576 from ccpp/bugfix-rdg-poll + +2018-05-02 17:54:57 +0200 akallabeth (3c51abc29) + + * Merge pull request #4612 from kevans91/mandest + +2018-05-02 09:59:33 -0500 Kyle Evans (5463b2359) + + * Enable 64-bit file support on FreeBSD as well + +2018-05-02 10:03:53 -0500 Kyle Evans (a7c0632bf) + + * Use SetFreeRDPCMakeInstallDir where CMake modules are installed + +2018-05-02 10:32:26 -0500 Kyle Evans (824ace49a) + + * Add SetFreeRDPCMakeInstallDir function to abstract away platform + differences + +2018-05-02 09:31:19 -0500 Kyle Evans (92a8e28f2) + + * Follow OpenBSD convention when installing manpages on FreeBSD + +2018-05-02 13:08:30 +0200 Armin Novak (3a5471310) + + * Fixed invalid argument parameter + +2018-05-02 13:08:17 +0200 Armin Novak (f631958a0) + + * Fixed argument warning. + +2018-05-02 12:57:34 +0200 Armin Novak (1fd5c53a7) + + * Fix #4597: Do string argument checks before a possible strtol + +2018-05-02 12:11:24 +0200 Martin Fleisz (fbb21e349) + + * Merge pull request #4608 from akallabeth/posix_timer_cmake_check + +2018-05-02 12:09:55 +0200 David Fort (9381e18cd) + + * Merge pull request #4570 from akallabeth/toolchain_fix + +2018-05-02 11:26:13 +0200 Martin Fleisz (31c804c34) + + * Merge pull request #4603 from hardening/socksplus + +2018-05-02 08:40:30 +0200 Armin Novak (60bf33f79) + + * Determine posix timer availability by function availability + +2018-04-29 21:25:28 +0200 David Fort (0f968b782) + + * proxy: cleanup SOCKS support and add user/password support + +2018-05-02 10:39:22 +0200 David Fort (a03c0d88d) + + * Merge pull request #4606 from kevans91/libressl-fixes + +2018-05-02 10:10:55 +0200 Martin Fleisz (c0804699f) + + * Merge pull request #4609 from akallabeth/clipboard_return_check + +2018-05-02 09:25:30 +0200 Armin Novak (e0af47d26) + + * Fixed rebase introduced error. + +2018-05-02 09:47:17 +0200 David Fort (2dee696af) + + * Merge pull request #4607 from kevans91/epoll + +2018-04-23 20:30:08 +0200 Jiri Sasek (1ba31551a) + + * socks proxy reply fix + +2018-05-02 09:21:42 +0200 Armin Novak (a1c3c1ad6) + + * Added proper return value checks for clipboard data. + +2018-04-04 13:40:13 +0200 Armin Novak (f19a17d3e) + + * Fixed surface bits command cleanup. + +2018-04-03 17:17:45 +0200 Armin Novak (4e6697261) + + * Fixed remaining global order buffers. + +2018-03-30 10:43:20 +0200 Armin Novak (e5767f07a) + + * Refactored order updates + +2018-05-01 23:50:15 -0500 Kyle Evans (aca530bc5) + + * Use shared memory instead of temp files on FreeBSD-compatible OS + +2018-05-01 23:42:25 -0500 Kyle Evans (45d8e2dfb) + + * Pull in libepoll-shim for the bits that require timerfd/epoll + +2018-05-01 23:38:48 -0500 Kyle Evans (5e9c8c4bc) + + * Set BSD/FREEBSD for DragonflyBSD + +2018-05-01 08:43:36 -0500 Kyle Evans (f8c391876) + + * Pull in the LibreSSL compatibility patches from FreeBSD + +2018-04-27 11:28:37 +0200 Armin Novak (bda925c52) + + * Added libavcodec version check for dsp-ffmpeg component. + +2018-04-27 09:39:30 +0200 David Fort (8cba20199) + + * Merge pull request #4548 from akallabeth/autoreconnect_fix + +2018-04-26 11:59:15 +0200 David Fort (782039c6a) + + * Merge pull request #4589 from oshogbo/token + +2018-04-26 02:11:04 -0700 p-pautov (fda76349b) + + * Fix Windows build. + +2018-04-17 17:05:20 -0700 Pavel Pautov (a0019ec79) + + * Fallback to RDG RPC transport only if server does not support RDG + HTTP and error out in other cases - invalid RDG SSL cert, + bad credentials, PAA failue, etc. + +2018-04-16 14:23:13 -0700 Pavel Pautov (c60388954) + + * Remove some unused functions. + +2018-04-12 13:05:04 -0700 Pavel Pautov (32505fda1) + + * Apply "authentication level" RDP property only to non-RDG + connections (as mstsc does). + +2018-04-11 20:02:44 -0700 Pavel Pautov (3a8d721bb) + + * Don't use CertificateName setting for RDG connections. + +2018-04-25 09:00:52 +0200 akallabeth (d5f9da2b3) + + * Merge pull request #4586 from Awingu/cbytes-fix + +2018-04-25 08:54:59 +0200 akallabeth (df1e3037e) + + * Merge pull request #4588 from oshogbo/tokencookie + +2018-04-24 20:45:52 +0200 Christian Plattner (4a19f4987) + + * Fail on unimplemented BIO_ctrl for /gt:rpc + +2018-04-24 16:35:04 +0200 Christian Plattner (4739189cf) + + * Implement BIO_ctrl more correctly for RDG + +2018-04-24 16:20:42 +0200 Christian Plattner (895689836) + + * Revert useless part of the bugfix + +2018-04-24 15:00:00 +0200 Mariusz Zaborski (651545388) + + * Recognize only the cookie format anything else treat as token. + +2018-04-24 14:34:45 +0200 Mariusz Zaborski (b9ddf2046) + + * Fix comments where is cookie and where is token. + +2018-04-24 10:33:44 +0200 Ruben De Visscher (1835a39aa) + + * Fix inconsistent cBytes value between WinScard and pcsc-lite. + +2017-08-18 19:17:17 +0200 Jiri Sasek (b1c1549ad) + + * SOCKS proxy support + +2018-04-19 11:04:08 +0200 Martin Fleisz (c5572b087) + + * Merge pull request #4539 from p-pautov/rdg_fixes + +2018-04-18 21:50:47 +0200 Christian Plattner (a15644365) + + * Fix BIO_get_fd for RDG, again. + +2018-04-18 14:50:31 +0200 Martin Fleisz (b228deb99) + + * Merge pull request #4543 from oshogbo/master + +2018-04-18 10:47:06 +0200 Christian Plattner (f9d036a87) + + * Fix #3602 by implementing BIO_get_fd correctly for RDG + +2018-04-18 10:38:42 +0200 Christian Plattner (589d2ec62) + + * Fix timeout for polling (partly fixes #3602) + +2018-04-17 15:03:27 +0200 Mariusz Zaborski (509afe252) + + * Remove MessageIntegrityCheck from context. + +2018-04-17 10:51:49 +0200 akallabeth (9de311fee) + + * Merge pull request #4572 from weberhofer/patch-1 + +2018-04-17 08:20:54 +0200 Johannes Weberhofer (277fc1ca4) + + * Include geometry.h in video channel + +2018-04-05 13:12:20 -0700 Pavel Pautov (c86692389) + + * Avoid buffer to struct cast. + +2018-04-04 19:08:26 -0700 Pavel Pautov (8fc0ea719) + + * Send correct packet size in case of PAA. Some cleanup. + +2018-04-04 19:08:20 -0700 Pavel Pautov (bbee19ced) + + * Content-Length and Transfer-Encoding are mutually exclusive. + +2018-04-04 19:08:08 -0700 Pavel Pautov (ec42228b2) + + * Consolidate IN/OUT data connections establishment into common + function and clean up related code. + +2018-04-04 19:08:00 -0700 Pavel Pautov (00256bba1) + + * Move NTLM auth related code into dedicated functions. + +2018-04-04 19:07:52 -0700 Pavel Pautov (269dec637) + + * Consolidate rdg_tls_out_connect/rdg_tls_in_connect into single + function. This also fixes connections to RDG server via + proxy. + +2018-04-04 19:07:33 -0700 Pavel Pautov (e639e2caf) + + * Removed unused "readEvent" - no one checks if it was set. Removed + needless rdg_check_event_handles declaration. + +2018-04-04 19:07:25 -0700 Pavel Pautov (1530bcf91) + + * Consolidate + rdg_send_in_channel_request/rdg_send_out_channel_request + into single function. + +2018-04-04 19:07:11 -0700 Pavel Pautov (0fbf8f895) + + * Explicitly skip "seed" payload on RDG OUT connection, to avoid + issues when it's split over several SSL records. + +2018-04-04 19:06:59 -0700 Pavel Pautov (44cb71049) + + * Moved some repeated "read all" code into function. + +2018-04-16 16:45:00 +0200 Armin Novak (1feca7768) + + * Fixed redirection with session brokers. + +2018-04-16 11:39:36 +0200 Armin Novak (927409cf8) + + * Add default values for keystore variables. + +2018-04-16 10:22:24 +0200 Armin Novak (8758638c2) + + * Ensure audin channel uses supported protocol version 1. + +2018-04-16 08:56:09 +0200 David Fort (d07d06b28) + + * rdpsnd: add support for wave2 PDU in client (#2) + +2018-04-12 16:52:33 +0200 Armin Novak (d8bcb6910) + + * Updated OpenSSL version in build scripts. + +2018-04-12 16:49:18 +0200 Armin Novak (887e94c58) + + * Added patch from f-droid repo. (Christian Plattner) + +2018-04-12 15:52:38 +0200 Bernhard Miklautz (fc6780a86) + + * Merge pull request #4567 from akallabeth/sanitizer_checks_refined + +2018-04-12 15:25:35 +0200 David Fort (81ea42098) + + * Merge pull request #4568 from akallabeth/rails_bad_window_fix + +2018-04-12 14:39:37 +0200 Armin Novak (5628ed5e7) + + * Check for window existence in remote app mode before access + +2018-04-12 11:49:43 +0200 Armin Novak (c9373cee0) + + * Refined checks for sanitizers. + +2018-04-12 12:10:56 +0200 Martin Fleisz (855af9e94) + + * Merge pull request #4557 from akallabeth/connect_error_fix + +2018-04-12 11:11:57 +0200 David Fort (14cce798e) + + * Merge pull request #4544 from oshogbo/nSize + +2018-04-12 10:43:34 +0200 Martin Fleisz (d1b4b410f) + + * Merge pull request #4547 from andreesteve/gatewayip + +2018-04-11 17:10:48 +0200 Martin Fleisz (e297a4f0e) + + * Merge pull request #4563 from oshogbo/pointer + +2018-04-11 16:01:45 +0200 Mariusz Zaborski (0e25335c8) + + * Don't assume that the pointer function are set. + +2018-04-11 14:45:35 +0200 Norbert Federa (648f66670) + + * Merge pull request #4561 from bmiklautz/200dev3 + +2018-04-11 13:36:33 +0200 Bernhard Miklautz (d309a1ba3) + + * build: set version to 2.0.0-dev3 + 2018-04-11 13:25:31 +0200 Martin Fleisz (7a7b18027) * Merge pull request #4560 from bmiklautz/200rc2 @@ -22,6 +2970,22 @@ * cmake: Fix finding OpenSSL 1.1.0 libs on Windows platforms +2018-04-11 09:30:40 +0200 Armin Novak (685f5a8d2) + + * Do not clear last error if not reconnecting. + +2018-04-11 09:00:32 +0200 Armin Novak (2fc31fcb3) + + * Set connection error if TCP connect fails. + +2018-04-11 08:33:05 +0200 Armin Novak (3606b66cc) + + * Fix rdpsnd channel detached handling. + +2018-03-14 22:37:30 -0700 Andre Esteve (d240069b5) + + * Gateway (RDG) use same IP for both channels + 2018-04-10 11:12:31 +0200 Martin Fleisz (04b29575f) * Merge pull request #4552 from perkerk/win-10-cursors-again @@ -38,6 +3002,10 @@ * Merge pull request #4551 from oshogbo/nego_0 +2018-04-09 17:28:22 +0200 Armin Novak (82ad911ee) + + * Added fake rdpsnd backend. + 2018-04-09 17:13:22 +0200 Mariusz Zaborski (480abdde9) * Fix setting of negotiated security protocol. @@ -50,10 +3018,61 @@ * Fix checking of krb in encrypt public key echo. +2018-04-09 14:03:05 +0200 Armin Novak (7af9ba917) + + * Refactored reconnect and redirect API + +2018-04-09 11:10:14 +0200 Armin Novak (030e9fc12) + + * Fixed channel duplicate disconnect handling + +2018-04-09 11:10:17 +0200 Armin Novak (6c7bfe892) + + * Fixed channel duplicate disconnect handling + +2018-04-09 11:10:08 +0200 Armin Novak (357391bd9) + + * Fixed channel duplicate disconnect handling + +2018-04-09 11:10:03 +0200 Armin Novak (1761a66b5) + + * Fixed channel duplicate disconnect handling + +2018-04-09 11:09:59 +0200 Armin Novak (d784954bc) + + * Fixed channel duplicate disconnect handling + +2018-04-09 11:09:56 +0200 Armin Novak (973a4c30b) + + * Fixed channel duplicate disconnect handling + +2018-04-09 11:09:51 +0200 Armin Novak (75717411d) + + * Fixed channel duplicate disconnect handling + +2018-04-09 11:08:46 +0200 Armin Novak (0a7691de5) + + * Fixed channel (dis)connect on redirect or reconnect. + +2018-04-09 11:04:27 +0200 Armin Novak (1698a54b0) + + * Removed unnecessarty string duplications. + 2018-04-09 09:22:18 +0200 David Fort (62f540812) * Merge pull request #4540 from akallabeth/warning_fixes_v2 +2018-04-06 21:15:15 +0200 Mariusz Zaborski (fe37fede5) + + * Fix variable passsed to HashCallback with MIC. The value in the + context is not set yet and we need one from authentication + message. + +2018-04-06 21:07:51 +0200 Mariusz Zaborski (00374382d) + + * There is no reason to restrict nSize to 2 the hostname can be empty + on UNIX-like machines. + 2018-04-06 11:34:24 +0200 Armin Novak (3762e0671) * Fixed RDP debug message invalid function. @@ -62,6 +3081,38 @@ * Added memory and thread sanitizer. +2018-04-03 12:08:01 +0200 Armin Novak (2c98d85a3) + + * Fixed function pointer typedef formatting. + +2018-04-03 11:18:22 +0200 Armin Novak (3f712cab7) + + * Fixed formatting of changed files. + +2018-03-23 13:57:22 +0100 Armin Novak (2e801a842) + + * Free dsp context on close. + +2018-03-23 13:26:17 +0100 Armin Novak (1c127fab7) + + * Added AudioFormatFlags fallback. + +2018-03-20 15:07:00 +0100 Armin Novak (ec5dab973) + + * Initialized ALSA backend format. + +2018-03-16 11:42:06 +0100 Armin Novak (65a82e9cd) + + * Fix #4462: Fallback typedef for AudioFormatID on MacOS < 10.10 + +2018-03-14 16:10:12 +0100 Armin Novak (4d45bd666) + + * Added CMake option WITH_DSP_EXPERIMENTAL + +2018-02-20 12:15:30 +0100 Armin Novak (f89c1857b) + + * Rewrite of sound and microphone channels + 2018-04-05 10:49:24 +0200 Armin Novak (b5668e35b) * Fixed format string mismatch. @@ -268,6 +3319,10 @@ * pkg freerdp-nightly: fix build on bionic +2018-03-20 11:31:53 +0100 Armin Novak (d8e8bf847) + + * Removed xrdp workarounds. + 2018-03-20 11:02:40 +0100 akallabeth (de83f4df2) * Merge pull request #4499 from mfleisz/cssp_v6 @@ -308,6 +3363,10 @@ * Added WaitableTimer implementation for mac OS. +2018-03-09 20:05:40 -0800 Lee Ball (d5cd7e8ff) + + * Updated project site link to HTTPS + 2018-03-09 14:25:45 +0100 Armin Novak (f430b55ab) * Detect command line flags in case RDP or MSINCIDENT files are used. @@ -412,6 +3471,14 @@ * Remove unnecessary WM_SETCURSOR handling from wf_event_proc +2018-03-05 09:59:41 +0100 Armin Novak (733f58c4f) + + * Use wrapper functions for input event handling. + +2018-03-05 09:59:26 +0100 Armin Novak (87c44a047) + + * Removed NULL checks in functions without return + 2018-03-02 12:42:04 -0600 Eric Brown (0c24ade66) * Misc fixes for Windows clients @@ -531,6 +3598,10 @@ * Merge pull request #4415 from akallabeth/drdynvc_dyn_log +2017-11-16 12:42:33 +0100 Armin Novak (84f2cff5e) + + * Fixed wayland issues. + 2018-02-14 15:54:13 +0100 Martin Fleisz (13be71381) * Merge pull request #4434 from akallabeth/winpr_digest_param diff --git a/README b/README index 0144d87..d1ad246 100644 --- a/README +++ b/README @@ -8,7 +8,7 @@ interoperability can finally liberate your computing experience. Resources --------- -Project website: http://www.freerdp.com/ +Project website: https://www.freerdp.com/ Issue tracker: https://github.com/FreeRDP/FreeRDP/issues Sources: https://github.com/FreeRDP/FreeRDP/ Downloads: https://pub.freerdp.com/releases/ diff --git a/channels/audin/client/alsa/audin_alsa.c b/channels/audin/client/alsa/audin_alsa.c index d821710..169422a 100644 --- a/channels/audin/client/alsa/audin_alsa.c +++ b/channels/audin/client/alsa/audin_alsa.c @@ -31,11 +31,11 @@ #include #include #include +#include #include #include -#include #include #include "audin_main.h" @@ -46,229 +46,129 @@ typedef struct _AudinALSADevice char* device_name; UINT32 frames_per_packet; - UINT32 target_rate; - UINT32 actual_rate; - snd_pcm_format_t format; - UINT32 target_channels; - UINT32 actual_channels; - int bytes_per_channel; - int wformat; - int block_size; - - FREERDP_DSP_CONTEXT* dsp_context; + AUDIO_FORMAT aformat; HANDLE thread; HANDLE stopEvent; - BYTE* buffer; - int buffer_frames; - AudinReceive receive; void* user_data; rdpContext* rdpcontext; + wLog* log; + int bytes_per_frame; } AudinALSADevice; +static snd_pcm_format_t audin_alsa_format(UINT32 wFormatTag, UINT32 bitPerChannel) +{ + switch (wFormatTag) + { + case WAVE_FORMAT_PCM: + switch (bitPerChannel) + { + case 16: + return SND_PCM_FORMAT_S16_LE; + + case 8: + return SND_PCM_FORMAT_S8; + + default: + return SND_PCM_FORMAT_UNKNOWN; + } + + case WAVE_FORMAT_ALAW: + return SND_PCM_FORMAT_A_LAW; + + case WAVE_FORMAT_MULAW: + return SND_PCM_FORMAT_MU_LAW; + + default: + return SND_PCM_FORMAT_UNKNOWN; + } +} + static BOOL audin_alsa_set_params(AudinALSADevice* alsa, snd_pcm_t* capture_handle) { int error; + UINT32 channels = alsa->aformat.nChannels; snd_pcm_hw_params_t* hw_params; + snd_pcm_format_t format = audin_alsa_format(alsa->aformat.wFormatTag, alsa->aformat.wBitsPerSample); if ((error = snd_pcm_hw_params_malloc(&hw_params)) < 0) { - WLog_ERR(TAG, "snd_pcm_hw_params_malloc (%s)", - snd_strerror(error)); + WLog_Print(alsa->log, WLOG_ERROR, "snd_pcm_hw_params_malloc (%s)", + snd_strerror(error)); return FALSE; } snd_pcm_hw_params_any(capture_handle, hw_params); snd_pcm_hw_params_set_access(capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); - snd_pcm_hw_params_set_format(capture_handle, hw_params, alsa->format); - snd_pcm_hw_params_set_rate_near(capture_handle, hw_params, &alsa->actual_rate, - NULL); + snd_pcm_hw_params_set_format(capture_handle, hw_params, format); + snd_pcm_hw_params_set_rate_near(capture_handle, hw_params, + &alsa->aformat.nSamplesPerSec, NULL); snd_pcm_hw_params_set_channels_near(capture_handle, hw_params, - &alsa->actual_channels); + &channels); snd_pcm_hw_params(capture_handle, hw_params); snd_pcm_hw_params_free(hw_params); snd_pcm_prepare(capture_handle); - - if ((alsa->actual_rate != alsa->target_rate) || - (alsa->actual_channels != alsa->target_channels)) - { - DEBUG_DVC("actual rate %"PRIu32" / channel %"PRIu32" is " - "different from target rate %"PRIu32" / channel %"PRIu32", resampling required.", - alsa->actual_rate, alsa->actual_channels, - alsa->target_rate, alsa->target_channels); - } - + alsa->aformat.nChannels = channels; + alsa->bytes_per_frame = snd_pcm_format_size(format, 1) * channels; return TRUE; } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT audin_alsa_thread_receive(AudinALSADevice* alsa, BYTE* src, - int size) -{ - int frames; - int cframes; - UINT ret = CHANNEL_RC_OK; - int encoded_size; - BYTE* encoded_data; - int rbytes_per_frame; - int tbytes_per_frame; - int status; - rbytes_per_frame = alsa->actual_channels * alsa->bytes_per_channel; - tbytes_per_frame = alsa->target_channels * alsa->bytes_per_channel; - - if ((alsa->target_rate == alsa->actual_rate) && - (alsa->target_channels == alsa->actual_channels)) - { - frames = size / rbytes_per_frame; - } - else - { - alsa->dsp_context->resample(alsa->dsp_context, src, alsa->bytes_per_channel, - alsa->actual_channels, alsa->actual_rate, size / rbytes_per_frame, - alsa->target_channels, alsa->target_rate); - frames = alsa->dsp_context->resampled_frames; - DEBUG_DVC("resampled %d frames at %"PRIu32" to %d frames at %"PRIu32"", - size / rbytes_per_frame, alsa->actual_rate, frames, alsa->target_rate); - src = alsa->dsp_context->resampled_buffer; - } - - while (frames > 0) - { - status = WaitForSingleObject(alsa->stopEvent, 0); - - if (status == WAIT_FAILED) - { - ret = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", ret); - break; - } - - if (status == WAIT_OBJECT_0) - break; - - cframes = alsa->frames_per_packet - alsa->buffer_frames; - - if (cframes > frames) - cframes = frames; - - CopyMemory(alsa->buffer + alsa->buffer_frames * tbytes_per_frame, src, - cframes * tbytes_per_frame); - alsa->buffer_frames += cframes; - - if (alsa->buffer_frames >= alsa->frames_per_packet) - { - if (alsa->wformat == WAVE_FORMAT_DVI_ADPCM) - { - if (!alsa->dsp_context->encode_ima_adpcm(alsa->dsp_context, - alsa->buffer, alsa->buffer_frames * tbytes_per_frame, - alsa->target_channels, alsa->block_size)) - { - ret = ERROR_INTERNAL_ERROR; - break; - } - - encoded_data = alsa->dsp_context->adpcm_buffer; - encoded_size = alsa->dsp_context->adpcm_size; - DEBUG_DVC("encoded %d to %d", - alsa->buffer_frames * tbytes_per_frame, encoded_size); - } - else - { - encoded_data = alsa->buffer; - encoded_size = alsa->buffer_frames * tbytes_per_frame; - } - - status = WaitForSingleObject(alsa->stopEvent, 0); - - if (status == WAIT_FAILED) - { - ret = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", ret); - break; - } - - if (status == WAIT_OBJECT_0) - break; - else - { - DEBUG_DVC("encoded %d [%d] to %d [%X]", alsa->buffer_frames, - tbytes_per_frame, encoded_size, - alsa->wformat); - ret = alsa->receive(encoded_data, encoded_size, alsa->user_data); - } - - alsa->buffer_frames = 0; - - if (ret != CHANNEL_RC_OK) - break; - } - - src += cframes * tbytes_per_frame; - frames -= cframes; - } - - return ret; -} - static DWORD WINAPI audin_alsa_thread_func(LPVOID arg) { long error; BYTE* buffer; - int rbytes_per_frame; snd_pcm_t* capture_handle = NULL; AudinALSADevice* alsa = (AudinALSADevice*) arg; DWORD status; - DEBUG_DVC("in"); - rbytes_per_frame = alsa->actual_channels * alsa->bytes_per_channel; - buffer = (BYTE*) calloc(alsa->frames_per_packet, rbytes_per_frame); - - if (!buffer) - { - WLog_ERR(TAG, "calloc failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto out; - } - - freerdp_dsp_context_reset_adpcm(alsa->dsp_context); + WLog_Print(alsa->log, WLOG_DEBUG, "in"); if ((error = snd_pcm_open(&capture_handle, alsa->device_name, SND_PCM_STREAM_CAPTURE, 0)) < 0) { - WLog_ERR(TAG, "snd_pcm_open (%s)", snd_strerror(error)); + WLog_Print(alsa->log, WLOG_ERROR, "snd_pcm_open (%s)", snd_strerror(error)); error = CHANNEL_RC_INITIALIZATION_ERROR; goto out; } if (!audin_alsa_set_params(alsa, capture_handle)) { - WLog_ERR(TAG, "audin_alsa_set_params failed"); + WLog_Print(alsa->log, WLOG_ERROR, "audin_alsa_set_params failed"); + goto out; + } + + buffer = (BYTE*) calloc(alsa->frames_per_packet + alsa->aformat.nBlockAlign, alsa->bytes_per_frame); + + if (!buffer) + { + WLog_Print(alsa->log, WLOG_ERROR, "calloc failed!"); + error = CHANNEL_RC_NO_MEMORY; goto out; } while (1) { + size_t frames = alsa->frames_per_packet; status = WaitForSingleObject(alsa->stopEvent, 0); if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %ld!", error); + WLog_Print(alsa->log, WLOG_ERROR, "WaitForSingleObject failed with error %ld!", error); break; } if (status == WAIT_OBJECT_0) break; - error = snd_pcm_readi(capture_handle, buffer, alsa->frames_per_packet); + error = snd_pcm_readi(capture_handle, buffer, frames); + + if (error == 0) + continue; if (error == -EPIPE) { @@ -277,13 +177,16 @@ static DWORD WINAPI audin_alsa_thread_func(LPVOID arg) } else if (error < 0) { - WLog_ERR(TAG, "snd_pcm_readi (%s)", snd_strerror(error)); + WLog_Print(alsa->log, WLOG_ERROR, "snd_pcm_readi (%s)", snd_strerror(error)); break; } - if ((error = audin_alsa_thread_receive(alsa, buffer, error * rbytes_per_frame))) + error = alsa->receive(&alsa->aformat, + buffer, error * alsa->bytes_per_frame, alsa->user_data); + + if (error) { - WLog_ERR(TAG, "audin_alsa_thread_receive failed with error %ld", error); + WLog_Print(alsa->log, WLOG_ERROR, "audin_alsa_thread_receive failed with error %ld", error); break; } } @@ -294,7 +197,7 @@ static DWORD WINAPI audin_alsa_thread_func(LPVOID arg) snd_pcm_close(capture_handle); out: - DEBUG_DVC("out"); + WLog_Print(alsa->log, WLOG_DEBUG, "out"); if (error && alsa->rdpcontext) setChannelError(alsa->rdpcontext, error, @@ -312,15 +215,20 @@ out: static UINT audin_alsa_free(IAudinDevice* device) { AudinALSADevice* alsa = (AudinALSADevice*) device; - freerdp_dsp_context_free(alsa->dsp_context); - free(alsa->device_name); + + if (alsa) + free(alsa->device_name); + free(alsa); return CHANNEL_RC_OK; } static BOOL audin_alsa_format_supported(IAudinDevice* device, - audinFormat* format) + const AUDIO_FORMAT* format) { + if (!device || !format) + return FALSE; + switch (format->wFormatTag) { case WAVE_FORMAT_PCM: @@ -334,15 +242,12 @@ static BOOL audin_alsa_format_supported(IAudinDevice* device, break; - case WAVE_FORMAT_DVI_ADPCM: - if ((format->nSamplesPerSec <= 48000) && - (format->wBitsPerSample == 4) && - (format->nChannels == 1 || format->nChannels == 2)) - { - return TRUE; - } + case WAVE_FORMAT_ALAW: + case WAVE_FORMAT_MULAW: + return TRUE; - break; + default: + return FALSE; } return FALSE; @@ -353,47 +258,20 @@ static BOOL audin_alsa_format_supported(IAudinDevice* device, * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_alsa_set_format(IAudinDevice* device, audinFormat* format, +static UINT audin_alsa_set_format(IAudinDevice* device, const AUDIO_FORMAT* format, UINT32 FramesPerPacket) { - int bs; AudinALSADevice* alsa = (AudinALSADevice*) device; - alsa->target_rate = format->nSamplesPerSec; - alsa->actual_rate = format->nSamplesPerSec; - alsa->target_channels = format->nChannels; - alsa->actual_channels = format->nChannels; - switch (format->wFormatTag) - { - case WAVE_FORMAT_PCM: - switch (format->wBitsPerSample) - { - case 8: - alsa->format = SND_PCM_FORMAT_S8; - alsa->bytes_per_channel = 1; - break; + if (!alsa || !format) + return ERROR_INVALID_PARAMETER; - case 16: - alsa->format = SND_PCM_FORMAT_S16_LE; - alsa->bytes_per_channel = 2; - break; - } + alsa->aformat = *format; + alsa->frames_per_packet = FramesPerPacket; - break; + if (audin_alsa_format(format->wFormatTag, format->wBitsPerSample) == SND_PCM_FORMAT_UNKNOWN) + return ERROR_INTERNAL_ERROR; - case WAVE_FORMAT_DVI_ADPCM: - alsa->format = SND_PCM_FORMAT_S16_LE; - alsa->bytes_per_channel = 2; - bs = (format->nBlockAlign - 4 * format->nChannels) * 4; - alsa->frames_per_packet = (alsa->frames_per_packet * format->nChannels * 2 / - bs + 1) * bs / (format->nChannels * 2); - DEBUG_DVC("aligned FramesPerPacket=%"PRIu32"", - alsa->frames_per_packet); - break; - } - - alsa->wformat = format->wFormatTag; - alsa->block_size = format->nBlockAlign; return CHANNEL_RC_OK; } @@ -405,38 +283,29 @@ static UINT audin_alsa_set_format(IAudinDevice* device, audinFormat* format, static UINT audin_alsa_open(IAudinDevice* device, AudinReceive receive, void* user_data) { - int tbytes_per_frame; AudinALSADevice* alsa = (AudinALSADevice*) device; + + if (!device || !receive || !user_data) + return ERROR_INVALID_PARAMETER; + alsa->receive = receive; alsa->user_data = user_data; - tbytes_per_frame = alsa->target_channels * alsa->bytes_per_channel; - alsa->buffer = (BYTE*) calloc(alsa->frames_per_packet, tbytes_per_frame); - - if (!alsa->buffer) - { - WLog_ERR(TAG, "calloc failed!"); - return ERROR_NOT_ENOUGH_MEMORY; - } - - alsa->buffer_frames = 0; if (!(alsa->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) { - WLog_ERR(TAG, "CreateEvent failed!"); + WLog_Print(alsa->log, WLOG_ERROR, "CreateEvent failed!"); goto error_out; } if (!(alsa->thread = CreateThread(NULL, 0, - audin_alsa_thread_func, alsa, 0, NULL))) + audin_alsa_thread_func, alsa, 0, NULL))) { - WLog_ERR(TAG, "CreateThread failed!"); + WLog_Print(alsa->log, WLOG_ERROR, "CreateThread failed!"); goto error_out; } return CHANNEL_RC_OK; error_out: - free(alsa->buffer); - alsa->buffer = NULL; CloseHandle(alsa->stopEvent); alsa->stopEvent = NULL; return ERROR_INTERNAL_ERROR; @@ -452,6 +321,9 @@ static UINT audin_alsa_close(IAudinDevice* device) UINT error = CHANNEL_RC_OK; AudinALSADevice* alsa = (AudinALSADevice*) device; + if (!alsa) + return ERROR_INVALID_PARAMETER; + if (alsa->stopEvent) { SetEvent(alsa->stopEvent); @@ -459,7 +331,7 @@ static UINT audin_alsa_close(IAudinDevice* device) if (WaitForSingleObject(alsa->thread, INFINITE) == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); + WLog_Print(alsa->log, WLOG_ERROR, "WaitForSingleObject failed with error %"PRIu32"", error); return error; } @@ -469,14 +341,12 @@ static UINT audin_alsa_close(IAudinDevice* device) alsa->thread = NULL; } - free(alsa->buffer); - alsa->buffer = NULL; alsa->receive = NULL; alsa->user_data = NULL; return error; } -COMMAND_LINE_ARGUMENT_A audin_alsa_args[] = +static COMMAND_LINE_ARGUMENT_A audin_alsa_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "audio device name" }, { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } @@ -496,7 +366,7 @@ static UINT audin_alsa_parse_addin_args(AudinALSADevice* device, AudinALSADevice* alsa = (AudinALSADevice*) device; flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, + status = CommandLineParseArgumentsA(args->argc, args->argv, audin_alsa_args, flags, alsa, NULL, NULL); if (status < 0) @@ -516,7 +386,7 @@ static UINT audin_alsa_parse_addin_args(AudinALSADevice* device, if (!alsa->device_name) { - WLog_ERR(TAG, "_strdup failed!"); + WLog_Print(alsa->log, WLOG_ERROR, "_strdup failed!"); return CHANNEL_RC_NO_MEMORY; } } @@ -552,6 +422,7 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS return CHANNEL_RC_NO_MEMORY; } + alsa->log = WLog_Get(TAG); alsa->iface.Open = audin_alsa_open; alsa->iface.FormatSupported = audin_alsa_format_supported; alsa->iface.SetFormat = audin_alsa_set_format; @@ -562,7 +433,8 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS if ((error = audin_alsa_parse_addin_args(alsa, args))) { - WLog_ERR(TAG, "audin_alsa_parse_addin_args failed with errorcode %"PRIu32"!", error); + WLog_Print(alsa->log, WLOG_ERROR, "audin_alsa_parse_addin_args failed with errorcode %"PRIu32"!", + error); goto error_out; } @@ -572,38 +444,27 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS if (!alsa->device_name) { - WLog_ERR(TAG, "_strdup failed!"); + WLog_Print(alsa->log, WLOG_ERROR, "_strdup failed!"); error = CHANNEL_RC_NO_MEMORY; goto error_out; } } alsa->frames_per_packet = 128; - alsa->target_rate = 22050; - alsa->actual_rate = 22050; - alsa->format = SND_PCM_FORMAT_S16_LE; - alsa->target_channels = 2; - alsa->actual_channels = 2; - alsa->bytes_per_channel = 2; - alsa->dsp_context = freerdp_dsp_context_new(); - - if (!alsa->dsp_context) - { - WLog_ERR(TAG, "freerdp_dsp_context_new failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto error_out; - } + alsa->aformat.nChannels = 2; + alsa->aformat.wBitsPerSample = 16; + alsa->aformat.wFormatTag = WAVE_FORMAT_PCM; + alsa->aformat.nSamplesPerSec = 44100; if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) alsa))) { - WLog_ERR(TAG, "RegisterAudinDevice failed with error %"PRIu32"!", error); + WLog_Print(alsa->log, WLOG_ERROR, "RegisterAudinDevice failed with error %"PRIu32"!", error); goto error_out; } return CHANNEL_RC_OK; error_out: - freerdp_dsp_context_free(alsa->dsp_context); free(alsa->device_name); free(alsa); return error; diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c index b04c258..b7ce330 100644 --- a/channels/audin/client/audin_main.c +++ b/channels/audin/client/audin_main.c @@ -32,11 +32,14 @@ #include #include -#include #include #include + +#include #include +#include + #include "audin_main.h" #define MSG_SNDIN_VERSION 0x01 @@ -70,7 +73,7 @@ struct _AUDIN_CHANNEL_CALLBACK * be stored as reference when the server sends the format index in * Open PDU and Format Change PDU */ - audinFormat* formats; + AUDIO_FORMAT* formats; UINT32 formats_count; }; @@ -82,9 +85,7 @@ struct _AUDIN_PLUGIN AUDIN_LISTENER_CALLBACK* listener_callback; /* Parsed plugin data */ - UINT16 fixed_format; - UINT16 fixed_channel; - UINT32 fixed_rate; + AUDIO_FORMAT* fixed_format; char* subsystem; char* device_name; @@ -93,23 +94,39 @@ struct _AUDIN_PLUGIN rdpContext* rdpcontext; BOOL attached; + wStream* data; + AUDIO_FORMAT* format; + UINT32 FramesPerPacket; + + FREERDP_DSP_CONTEXT* dsp_context; wLog* log; }; static BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args); -static UINT audin_write_and_free_stream(AUDIN_CHANNEL_CALLBACK* callback, wStream* s) +static UINT audin_channel_write_and_free(AUDIN_CHANNEL_CALLBACK* callback, wStream* out, + BOOL freeStream) { - UINT error = ERROR_INTERNAL_ERROR; - const size_t length = Stream_GetPosition(s); - const BYTE* data = Stream_Buffer(s); + UINT error; - if (callback && callback->channel && callback->channel->Write) - error = callback->channel->Write(callback->channel, length, data, NULL); + if (!callback || !out) + return ERROR_INVALID_PARAMETER; + + if (!callback->channel || !callback->channel->Write) + return ERROR_INTERNAL_ERROR; + + Stream_SealLength(out); + error = callback->channel->Write(callback->channel, + Stream_Length(out), + Stream_Buffer(out), NULL); + + if (freeStream) + Stream_Free(out, TRUE); - Stream_Free(s, TRUE); return error; } + + /** * Function description * @@ -118,9 +135,25 @@ static UINT audin_write_and_free_stream(AUDIN_CHANNEL_CALLBACK* callback, wStrea static UINT audin_process_version(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback, wStream* s) { wStream* out; - UINT32 Version; - Stream_Read_UINT32(s, Version); - DEBUG_DVC("Version=%"PRIu32"", Version); + const UINT32 ClientVersion = 0x01; + UINT32 ServerVersion; + + if (Stream_GetRemainingLength(s) < 4) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, ServerVersion); + WLog_Print(audin->log, WLOG_DEBUG, "ServerVersion=%"PRIu32", ClientVersion=%"PRIu32, ServerVersion, + ClientVersion); + + /* Do not answer server packet, we do not support the channel version. */ + if (ServerVersion != ClientVersion) + { + WLog_Print(audin->log, WLOG_WARN, + "Incompatible channel version server=%"PRIu32", client supports version=%"PRIu32, ServerVersion, + ClientVersion); + return CHANNEL_RC_OK; + } + out = Stream_New(NULL, 5); if (!out) @@ -130,8 +163,8 @@ static UINT audin_process_version(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c } Stream_Write_UINT8(out, MSG_SNDIN_VERSION); - Stream_Write_UINT32(out, Version); - return audin_write_and_free_stream(callback, out); + Stream_Write_UINT32(out, ClientVersion); + return audin_channel_write_and_free(callback, out, TRUE); } /** @@ -157,18 +190,16 @@ static UINT audin_send_incoming_data_pdu(AUDIN_CHANNEL_CALLBACK* callback) static UINT audin_process_formats(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback, wStream* s) { UINT32 i; - BYTE* fm; UINT error; wStream* out; UINT32 NumFormats; - audinFormat format; - size_t cbSizeFormatsPacket; + UINT32 cbSizeFormatsPacket; if (Stream_GetRemainingLength(s) < 8) - return ERROR_NO_DATA; + return ERROR_INVALID_DATA; Stream_Read_UINT32(s, NumFormats); - DEBUG_DVC("NumFormats %"PRIu32"", NumFormats); + WLog_Print(audin->log, WLOG_DEBUG, "NumFormats %"PRIu32"", NumFormats); if ((NumFormats < 1) || (NumFormats > 1000)) { @@ -177,7 +208,7 @@ static UINT audin_process_formats(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c } Stream_Seek_UINT32(s); /* cbSizeFormatsPacket */ - callback->formats = (audinFormat*) calloc(NumFormats, sizeof(audinFormat)); + callback->formats = audio_formats_new(NumFormats); if (!callback->formats) { @@ -199,52 +230,38 @@ static UINT audin_process_formats(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c /* SoundFormats (variable) */ for (i = 0; i < NumFormats; i++) { - if (Stream_GetRemainingLength(s) < 18) - return ERROR_NO_DATA; + AUDIO_FORMAT format = { 0 }; - Stream_GetPointer(s, fm); - Stream_Read_UINT16(s, format.wFormatTag); - Stream_Read_UINT16(s, format.nChannels); - Stream_Read_UINT32(s, format.nSamplesPerSec); - Stream_Seek_UINT32(s); /* nAvgBytesPerSec */ - Stream_Read_UINT16(s, format.nBlockAlign); - Stream_Read_UINT16(s, format.wBitsPerSample); - Stream_Read_UINT16(s, format.cbSize); - format.data = Stream_Pointer(s); - - if (Stream_GetRemainingLength(s) < format.cbSize) - return ERROR_NO_DATA; - - Stream_Seek(s, format.cbSize); - DEBUG_DVC("wFormatTag=%"PRIu16" nChannels=%"PRIu16" nSamplesPerSec=%"PRIu32" " - "nBlockAlign=%"PRIu16" wBitsPerSample=%"PRIu16" cbSize=%"PRIu16"", - format.wFormatTag, format.nChannels, format.nSamplesPerSec, - format.nBlockAlign, format.wBitsPerSample, format.cbSize); - - if (audin->fixed_format > 0 && audin->fixed_format != format.wFormatTag) - continue; - - if (audin->fixed_channel > 0 && audin->fixed_channel != format.nChannels) - continue; - - if (audin->fixed_rate > 0 && audin->fixed_rate != format.nSamplesPerSec) - continue; - - if (audin->device && audin->device->FormatSupported(audin->device, &format)) + if (!audio_format_read(s, &format)) + { + error = ERROR_INVALID_DATA; + goto out; + } + + audio_format_print(audin->log, WLOG_DEBUG, &format); + + if (!audio_format_compatible(audin->fixed_format, &format)) + { + audio_format_free(&format); + continue; + } + + if (freerdp_dsp_supports_format(&format, TRUE) || + audin->device->FormatSupported(audin->device, &format)) { - DEBUG_DVC("format ok"); /* Store the agreed format in the corresponding index */ callback->formats[callback->formats_count++] = format; - /* Put the format to output buffer */ - if (!Stream_EnsureRemainingCapacity(out, 18 + format.cbSize)) + if (!audio_format_write(out, &format)) { error = CHANNEL_RC_NO_MEMORY; WLog_Print(audin->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); goto out; } - - Stream_Write(out, fm, 18 + format.cbSize); + } + else + { + audio_format_free(&format); } } @@ -254,21 +271,22 @@ static UINT audin_process_formats(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c goto out; } - cbSizeFormatsPacket = Stream_GetPosition(out); + cbSizeFormatsPacket = (UINT32) Stream_GetPosition(out); Stream_SetPosition(out, 0); Stream_Write_UINT8(out, MSG_SNDIN_FORMATS); /* Header (1 byte) */ Stream_Write_UINT32(out, callback->formats_count); /* NumFormats (4 bytes) */ Stream_Write_UINT32(out, cbSizeFormatsPacket); /* cbSizeFormatsPacket (4 bytes) */ Stream_SetPosition(out, cbSizeFormatsPacket); - error = audin_write_and_free_stream(callback, out); + error = audin_channel_write_and_free(callback, out, FALSE); out: if (error != CHANNEL_RC_OK) { - free(callback->formats); + audio_formats_free(callback->formats, NumFormats); callback->formats = NULL; } + Stream_Free(out, TRUE); return error; } @@ -290,7 +308,7 @@ static UINT audin_send_format_change_pdu(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALL Stream_Write_UINT8(out, MSG_SNDIN_FORMATCHANGE); Stream_Write_UINT32(out, NewFormat); - return audin_write_and_free_stream(callback, out); + return audin_channel_write_and_free(callback, out, TRUE); } /** @@ -311,7 +329,7 @@ static UINT audin_send_open_reply_pdu(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBAC Stream_Write_UINT8(out, MSG_SNDIN_OPEN_REPLY); Stream_Write_UINT32(out, Result); - return audin_write_and_free_stream(callback, out); + return audin_channel_write_and_free(callback, out, TRUE); } /** @@ -319,10 +337,11 @@ static UINT audin_send_open_reply_pdu(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBAC * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_receive_wave_data(const BYTE* data, int size, void* user_data) +static UINT audin_receive_wave_data(const AUDIO_FORMAT* format, + const BYTE* data, size_t size, void* user_data) { UINT error; - wStream* out; + BOOL compatible; AUDIN_PLUGIN* audin; AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) user_data; @@ -337,25 +356,114 @@ static UINT audin_receive_wave_data(const BYTE* data, int size, void* user_data) if (!audin->attached) return CHANNEL_RC_OK; + Stream_SetPosition(audin->data, 0); + + if (!Stream_EnsureRemainingCapacity(audin->data, 1)) + return CHANNEL_RC_NO_MEMORY; + + Stream_Write_UINT8(audin->data, MSG_SNDIN_DATA); + + compatible = audio_format_compatible(format, audin->format); + if (compatible && audin->device->FormatSupported(audin->device, audin->format)) + { + if (!Stream_EnsureRemainingCapacity(audin->data, size)) + return CHANNEL_RC_NO_MEMORY; + + Stream_Write(audin->data, data, size); + } + else + { + if (!freerdp_dsp_encode(audin->dsp_context, format, data, size, audin->data)) + return ERROR_INTERNAL_ERROR; + } + + /* Did not encode anything, skip this, the codec is not ready for output. */ + if (Stream_GetPosition(audin->data) <= 1) + return CHANNEL_RC_OK; + + audio_format_print(audin->log, WLOG_TRACE, audin->format); + WLog_Print(audin->log, WLOG_TRACE, "[%"PRIdz"/%"PRIdz"]", size, + Stream_GetPosition(audin->data) - 1); + if ((error = audin_send_incoming_data_pdu(callback))) { WLog_Print(audin->log, WLOG_ERROR, "audin_send_incoming_data_pdu failed!"); return error; } - out = Stream_New(NULL, size + 1); - - if (!out) - { - WLog_Print(audin->log, WLOG_ERROR, "Stream_New failed!"); - return ERROR_NOT_ENOUGH_MEMORY; - } - - Stream_Write_UINT8(out, MSG_SNDIN_DATA); - Stream_Write(out, data, size); - return audin_write_and_free_stream(callback, out); + return audin_channel_write_and_free(callback, audin->data, FALSE); } +static BOOL audin_open_device(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback) +{ + UINT error = ERROR_INTERNAL_ERROR; + BOOL supported; + AUDIO_FORMAT format; + + if (!audin || !audin->device) + return FALSE; + + format = *audin->format; + supported = IFCALLRESULT(FALSE, audin->device->FormatSupported, audin->device, &format); + WLog_Print(audin->log, WLOG_DEBUG, "microphone uses %s codec", + audio_format_get_tag_string(format.wFormatTag)); + + if (!supported) + { + /* Default sample rates supported by most backends. */ + const UINT32 samplerates[] = { + 96000, + 48000, + 44100, + 22050 + }; + BOOL test = FALSE; + + format.wFormatTag = WAVE_FORMAT_PCM; + format.wBitsPerSample = 16; + test = IFCALLRESULT(FALSE, audin->device->FormatSupported, audin->device, &format); + if (!test) + { + size_t x; + for (x=0; xdevice->FormatSupported, audin->device, &format); + if (test) + break; + } + } + if (!test) + return FALSE; + } + + IFCALLRET(audin->device->SetFormat, error, + audin->device, &format, + audin->FramesPerPacket); + + if (error != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "SetFormat failed with errorcode %"PRIu32"", error); + return FALSE; + } + + if (!supported) + { + if (!freerdp_dsp_context_reset(audin->dsp_context, audin->format)) + return FALSE; + } + + IFCALLRET(audin->device->Open, error, audin->device, + audin_receive_wave_data, callback); + + if (error != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "Open failed with errorcode %"PRIu32"", error); + return FALSE; + } + + return TRUE; +} /** * Function description * @@ -363,49 +471,30 @@ static UINT audin_receive_wave_data(const BYTE* data, int size, void* user_data) */ static UINT audin_process_open(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback, wStream* s) { - audinFormat* format; UINT32 initialFormat; UINT32 FramesPerPacket; UINT error = CHANNEL_RC_OK; - if (!audin || !callback || !s) - return ERROR_INTERNAL_ERROR; - if (Stream_GetRemainingLength(s) < 8) - return ERROR_NO_DATA; + return ERROR_INVALID_DATA; Stream_Read_UINT32(s, FramesPerPacket); Stream_Read_UINT32(s, initialFormat); - DEBUG_DVC("FramesPerPacket=%"PRIu32" initialFormat=%"PRIu32"", - FramesPerPacket, initialFormat); + WLog_Print(audin->log, WLOG_DEBUG, "FramesPerPacket=%"PRIu32" initialFormat=%"PRIu32"", + FramesPerPacket, initialFormat); + audin->FramesPerPacket = FramesPerPacket; - if (initialFormat >= (UINT32) callback->formats_count) + if (initialFormat >= callback->formats_count) { WLog_Print(audin->log, WLOG_ERROR, "invalid format index %"PRIu32" (total %d)", initialFormat, callback->formats_count); return ERROR_INVALID_DATA; } - format = &callback->formats[initialFormat]; + audin->format = &callback->formats[initialFormat]; - if (audin->device) - { - IFCALLRET(audin->device->SetFormat, error, audin->device, format, FramesPerPacket); - - if (error != CHANNEL_RC_OK) - { - WLog_Print(audin->log, WLOG_ERROR, "SetFormat failed with errorcode %"PRIu32"", error); - return error; - } - - IFCALLRET(audin->device->Open, error, audin->device, audin_receive_wave_data, callback); - - if (error != CHANNEL_RC_OK) - { - WLog_Print(audin->log, WLOG_ERROR, "Open failed with errorcode %"PRIu32"", error); - return error; - } - } + if (!audin_open_device(audin, callback)) + return ERROR_INTERNAL_ERROR; if ((error = audin_send_format_change_pdu(audin, callback, initialFormat))) { @@ -428,17 +517,13 @@ static UINT audin_process_format_change(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLB wStream* s) { UINT32 NewFormat; - audinFormat* format; UINT error = CHANNEL_RC_OK; - if (!audin || !callback || !s) - return ERROR_INTERNAL_ERROR; - if (Stream_GetRemainingLength(s) < 4) - return ERROR_NO_DATA; + return ERROR_INVALID_DATA; Stream_Read_UINT32(s, NewFormat); - DEBUG_DVC("NewFormat=%"PRIu32"", NewFormat); + WLog_Print(audin->log, WLOG_DEBUG, "NewFormat=%"PRIu32"", NewFormat); if (NewFormat >= callback->formats_count) { @@ -447,7 +532,7 @@ static UINT audin_process_format_change(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLB return ERROR_INVALID_DATA; } - format = &callback->formats[NewFormat]; + audin->format = &callback->formats[NewFormat]; if (audin->device) { @@ -455,29 +540,16 @@ static UINT audin_process_format_change(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLB if (error != CHANNEL_RC_OK) { - WLog_Print(audin->log, WLOG_ERROR, "Close failed with errorcode %"PRIu32"", error); - return error; - } - - IFCALLRET(audin->device->SetFormat, error, audin->device, format, 0); - - if (error != CHANNEL_RC_OK) - { - WLog_Print(audin->log, WLOG_ERROR, "SetFormat failed with errorcode %"PRIu32"", error); - return error; - } - - IFCALLRET(audin->device->Open, error, audin->device, audin_receive_wave_data, callback); - - if (error != CHANNEL_RC_OK) - { - WLog_Print(audin->log, WLOG_ERROR, "Open failed with errorcode %"PRIu32"", error); + WLog_ERR(TAG, "Close failed with errorcode %"PRIu32"", error); return error; } } + if (!audin_open_device(audin, callback)) + return ERROR_INTERNAL_ERROR; + if ((error = audin_send_format_change_pdu(audin, callback, NewFormat))) - WLog_Print(audin->log, WLOG_ERROR, "audin_send_format_change_pdu failed!"); + WLog_ERR(TAG, "audin_send_format_change_pdu failed!"); return error; } @@ -506,7 +578,7 @@ static UINT audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, return ERROR_NO_DATA; Stream_Read_UINT8(data, MessageId); - DEBUG_DVC("MessageId=0x%02"PRIx8"", MessageId); + WLog_Print(audin->log, WLOG_DEBUG, "MessageId=0x%02"PRIx8"", MessageId); switch (MessageId) { @@ -545,7 +617,7 @@ static UINT audin_on_close(IWTSVirtualChannelCallback* pChannelCallback) AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback; AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin; UINT error = CHANNEL_RC_OK; - DEBUG_DVC("..."); + WLog_Print(audin->log, WLOG_TRACE, "..."); if (audin->device) { @@ -555,7 +627,8 @@ static UINT audin_on_close(IWTSVirtualChannelCallback* pChannelCallback) WLog_Print(audin->log, WLOG_ERROR, "Close failed with errorcode %"PRIu32"", error); } - free(callback->formats); + audin->format = NULL; + audio_formats_free(callback->formats, callback->formats_count); free(callback); return error; } @@ -577,7 +650,7 @@ static UINT audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallb return ERROR_INTERNAL_ERROR; audin = (AUDIN_PLUGIN*) listener_callback->plugin; - DEBUG_DVC("..."); + WLog_Print(audin->log, WLOG_TRACE, "..."); callback = (AUDIN_CHANNEL_CALLBACK*) calloc(1, sizeof(AUDIN_CHANNEL_CALLBACK)); if (!callback) @@ -603,7 +676,14 @@ static UINT audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallb static UINT audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr) { AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin; - DEBUG_DVC("..."); + + if (!audin) + return CHANNEL_RC_BAD_CHANNEL_HANDLE; + + if (!pChannelMgr) + return ERROR_INVALID_PARAMETER; + + WLog_Print(audin->log, WLOG_TRACE, "..."); audin->listener_callback = (AUDIN_LISTENER_CALLBACK*) calloc(1, sizeof(AUDIN_LISTENER_CALLBACK)); if (!audin->listener_callback) @@ -628,7 +708,12 @@ static UINT audin_plugin_terminated(IWTSPlugin* pPlugin) { AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin; UINT error = CHANNEL_RC_OK; - DEBUG_DVC("..."); + + if (!audin) + return CHANNEL_RC_BAD_CHANNEL_HANDLE; + + WLog_Print(audin->log, WLOG_TRACE, "..."); + audio_format_free(audin->fixed_format); if (audin->device) { @@ -643,10 +728,10 @@ static UINT audin_plugin_terminated(IWTSPlugin* pPlugin) audin->device = NULL; } + freerdp_dsp_context_free(audin->dsp_context); + Stream_Free(audin->data, TRUE); free(audin->subsystem); - audin->subsystem = NULL; free(audin->device_name); - audin->device_name = NULL; free(audin->listener_callback); free(audin); return CHANNEL_RC_OK; @@ -691,7 +776,7 @@ static UINT audin_register_device_plugin(IWTSPlugin* pPlugin, IAudinDevice* devi return ERROR_ALREADY_EXISTS; } - DEBUG_DVC("device registered."); + WLog_Print(audin->log, WLOG_DEBUG, "device registered."); audin->device = device; return CHANNEL_RC_OK; } @@ -706,7 +791,7 @@ static UINT audin_load_device_plugin(AUDIN_PLUGIN* audin, char* name, ADDIN_ARGV PFREERDP_AUDIN_DEVICE_ENTRY entry; FREERDP_AUDIN_DEVICE_ENTRY_POINTS entryPoints; UINT error; - entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_channel_addin_entry("audin", name, NULL, + entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_channel_addin_entry("audin", (LPSTR) name, NULL, 0); if (entry == NULL) @@ -756,7 +841,7 @@ static UINT audin_set_subsystem(AUDIN_PLUGIN* audin, const char* subsystem) * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_set_device_name(AUDIN_PLUGIN* audin, char* device_name) +static UINT audin_set_device_name(AUDIN_PLUGIN* audin, const char* device_name) { free(audin->device_name); audin->device_name = _strdup(device_name); @@ -791,7 +876,7 @@ BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args) return TRUE; flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, + status = CommandLineParseArgumentsA(args->argc, args->argv, audin_args, flags, audin, NULL, NULL); if (status != 0) @@ -829,7 +914,7 @@ BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args) if ((errno != 0) || (val > UINT16_MAX)) return FALSE; - audin->fixed_format = val; + audin->fixed_format->wFormatTag = val; } CommandLineSwitchCase(arg, "rate") { @@ -838,14 +923,14 @@ BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args) if ((errno != 0) || (val < INT32_MIN) || (val > INT32_MAX)) return FALSE; - audin->fixed_rate = val; + audin->fixed_format->nSamplesPerSec = val; } CommandLineSwitchCase(arg, "channel") { unsigned long val = strtoul(arg->Value, NULL, 0); if ((errno != 0) || (val > UINT16_MAX)) - audin->fixed_channel = val; + audin->fixed_format->nChannels = val; } CommandLineSwitchDefault(arg) { @@ -917,6 +1002,20 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) } audin->log = WLog_Get(TAG); + audin->data = Stream_New(NULL, 4096); + audin->fixed_format = audio_format_new(); + + if (!audin->fixed_format) + goto out; + + if (!audin->data) + goto out; + + audin->dsp_context = freerdp_dsp_context_new(TRUE); + + if (!audin->dsp_context) + goto out; + audin->attached = TRUE; audin->iface.Initialize = audin_plugin_initialize; audin->iface.Connected = NULL; diff --git a/channels/audin/client/audin_main.h b/channels/audin/client/audin_main.h index 419986c..83a75a4 100644 --- a/channels/audin/client/audin_main.h +++ b/channels/audin/client/audin_main.h @@ -32,11 +32,5 @@ #define TAG CHANNELS_TAG("audin.client") -#ifdef WITH_DEBUG_DVC -#define DEBUG_DVC(...) WLog_DBG(TAG, __VA_ARGS__) -#else -#define DEBUG_DVC(...) do { } while (0) -#endif - #endif /* FREERDP_CHANNEL_AUDIN_CLIENT_MAIN_H */ diff --git a/channels/audin/client/mac/audin_mac.c b/channels/audin/client/mac/audin_mac.c index d357838..40ba05d 100644 --- a/channels/audin/client/mac/audin_mac.c +++ b/channels/audin/client/mac/audin_mac.c @@ -42,85 +42,79 @@ #include #include -#include #include #include "audin_main.h" #define MAC_AUDIO_QUEUE_NUM_BUFFERS 100 -#define MAC_AUDIO_QUEUE_BUFFER_SIZE 32768 + +/* Fix for #4462: Provide type alias if not declared (Mac OS < 10.10) + * https://developer.apple.com/documentation/coreaudio/audioformatid + */ +#ifndef AudioFormatID +typedef UInt32 AudioFormatID; +#endif + +#ifndef AudioFormatFlags +typedef UInt32 AudioFormatFlags; +#endif typedef struct _AudinMacDevice { - IAudinDevice iface; + IAudinDevice iface; - FREERDP_DSP_CONTEXT* dsp_context; + AUDIO_FORMAT format; + UINT32 FramesPerPacket; + int dev_unit; - audinFormat format; - UINT32 FramesPerPacket; - int dev_unit; + AudinReceive receive; + void* user_data; - AudinReceive receive; - void* user_data; + rdpContext* rdpcontext; - rdpContext* rdpcontext; - - bool isOpen; - AudioQueueRef audioQueue; - AudioStreamBasicDescription audioFormat; - AudioQueueBufferRef audioBuffers[MAC_AUDIO_QUEUE_NUM_BUFFERS]; + bool isOpen; + AudioQueueRef audioQueue; + AudioStreamBasicDescription audioFormat; + AudioQueueBufferRef audioBuffers[MAC_AUDIO_QUEUE_NUM_BUFFERS]; } AudinMacDevice; -static AudioFormatID audin_mac_get_format(const audinFormat* format) +static AudioFormatID audin_mac_get_format(const AUDIO_FORMAT* format) { - switch (format->wFormatTag) - { - case WAVE_FORMAT_PCM: - return kAudioFormatLinearPCM; - /* - case WAVE_FORMAT_GSM610: - return kAudioFormatMicrosoftGSM; - case WAVE_FORMAT_ALAW: - return kAudioFormatALaw; - case WAVE_FORMAT_MULAW: - return kAudioFormatULaw; - case WAVE_FORMAT_AAC_MS: - return kAudioFormatMPEG4AAC; - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - return kAudioFormatLinearPCM; - */ - } + switch (format->wFormatTag) + { + case WAVE_FORMAT_PCM: + return kAudioFormatLinearPCM; - return 0; + default: + return 0; + } } -static AudioFormatFlags audin_mac_get_flags_for_format(const audinFormat* format) +static AudioFormatFlags audin_mac_get_flags_for_format(const AUDIO_FORMAT* format) { - switch(format->wFormatTag) - { - case WAVE_FORMAT_DVI_ADPCM: - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_PCM: - return kAudioFormatFlagIsSignedInteger; - default: - return 0; - } + switch (format->wFormatTag) + { + case WAVE_FORMAT_PCM: + return kAudioFormatFlagIsSignedInteger; + + default: + return 0; + } } -static BOOL audin_mac_format_supported(IAudinDevice* device, audinFormat* format) +static BOOL audin_mac_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format) { - AudioFormatID req_fmt = 0; + AudioFormatID req_fmt = 0; - if (device == NULL || format == NULL) - return FALSE; + if (device == NULL || format == NULL) + return FALSE; - req_fmt = audin_mac_get_format(format); + req_fmt = audin_mac_get_format(format); - if (req_fmt == 0) - return FALSE; + if (req_fmt == 0) + return FALSE; - return TRUE; + return TRUE; } /** @@ -128,279 +122,246 @@ static BOOL audin_mac_format_supported(IAudinDevice* device, audinFormat* format * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_mac_set_format(IAudinDevice* device, audinFormat* format, UINT32 FramesPerPacket) +static UINT audin_mac_set_format(IAudinDevice* device, const AUDIO_FORMAT* format, + UINT32 FramesPerPacket) { - AudinMacDevice* mac = (AudinMacDevice*)device; + AudinMacDevice* mac = (AudinMacDevice*)device; - if (device == NULL || format == NULL) - return ERROR_INVALID_PARAMETER; + if (device == NULL || format == NULL) + return ERROR_INVALID_PARAMETER; - mac->FramesPerPacket = FramesPerPacket; - CopyMemory(&(mac->format), format, sizeof(audinFormat)); + mac->FramesPerPacket = FramesPerPacket; + mac->format = *format; + WLog_INFO(TAG, "Audio Format %s [channels=%d, samples=%d, bits=%d]", + audio_format_get_tag_string(format->wFormatTag), + format->nChannels, format->nSamplesPerSec, format->wBitsPerSample); + mac->audioFormat.mBitsPerChannel = format->wBitsPerSample; - WLog_INFO(TAG, "Audio Format %s [channels=%d, samples=%d, bits=%d]", - rdpsnd_get_audio_tag_string(format->wFormatTag), - format->nChannels, format->nSamplesPerSec, format->wBitsPerSample); + if (format->wBitsPerSample == 0) + mac->audioFormat.mBitsPerChannel = 16; - switch (format->wFormatTag) - { - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - mac->FramesPerPacket *= 4; /* Compression ratio. */ - mac->format.wBitsPerSample *= 4; - break; - } - - mac->audioFormat.mBitsPerChannel = mac->format.wBitsPerSample; - mac->audioFormat.mChannelsPerFrame = mac->format.nChannels; - mac->audioFormat.mFormatFlags = audin_mac_get_flags_for_format(format); - mac->audioFormat.mFormatID = audin_mac_get_format(format); - mac->audioFormat.mFramesPerPacket = 1; - mac->audioFormat.mSampleRate = mac->format.nSamplesPerSec; - mac->audioFormat.mBytesPerFrame = - mac->audioFormat.mChannelsPerFrame * mac->audioFormat.mBitsPerChannel / 8; - mac->audioFormat.mBytesPerPacket = - mac->audioFormat.mBytesPerFrame * mac->audioFormat.mFramesPerPacket; - - return CHANNEL_RC_OK; + mac->audioFormat.mBytesPerFrame = 0; + mac->audioFormat.mBytesPerPacket = 0; + mac->audioFormat.mChannelsPerFrame = mac->format.nChannels; + mac->audioFormat.mFormatFlags = audin_mac_get_flags_for_format(format); + mac->audioFormat.mFormatID = audin_mac_get_format(format); + mac->audioFormat.mFramesPerPacket = 1; + mac->audioFormat.mReserved = 0; + mac->audioFormat.mSampleRate = mac->format.nSamplesPerSec; + return CHANNEL_RC_OK; } -static void mac_audio_queue_input_cb(void *aqData, +static void mac_audio_queue_input_cb(void* aqData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer, - const AudioTimeStamp *inStartTime, + const AudioTimeStamp* inStartTime, UInt32 inNumPackets, - const AudioStreamPacketDescription *inPacketDesc) + const AudioStreamPacketDescription* inPacketDesc) { - AudinMacDevice* mac = (AudinMacDevice*)aqData; - UINT error; - int encoded_size = 0; - const BYTE *encoded_data; - BYTE *buffer = inBuffer->mAudioData; - int buffer_size = inBuffer->mAudioDataByteSize; + AudinMacDevice* mac = (AudinMacDevice*)aqData; + UINT error = CHANNEL_RC_OK; + const BYTE* buffer = inBuffer->mAudioData; + int buffer_size = inBuffer->mAudioDataByteSize; + (void)inAQ; + (void)inStartTime; + (void)inNumPackets; + (void)inPacketDesc; - (void)inAQ; - (void)inStartTime; - (void)inNumPackets; - (void)inPacketDesc; + if (buffer_size > 0) + error = mac->receive(&mac->format, buffer, buffer_size, mac->user_data); + AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL); - /* Process. */ - switch (mac->format.wFormatTag) { - case WAVE_FORMAT_ADPCM: - if (!mac->dsp_context->encode_ms_adpcm(mac->dsp_context, - buffer, buffer_size, mac->format.nChannels, mac->format.nBlockAlign)) - { - SetLastError(ERROR_INTERNAL_ERROR); - return; - } - encoded_data = mac->dsp_context->adpcm_buffer; - encoded_size = mac->dsp_context->adpcm_size; - break; - case WAVE_FORMAT_DVI_ADPCM: - if (!mac->dsp_context->encode_ima_adpcm(mac->dsp_context, - buffer, buffer_size, mac->format.nChannels, mac->format.nBlockAlign)) - { - SetLastError(ERROR_INTERNAL_ERROR); - break; - } - encoded_data = mac->dsp_context->adpcm_buffer; - encoded_size = mac->dsp_context->adpcm_size; - break; - default: - encoded_data = buffer; - encoded_size = buffer_size; - break; - } - - if ((error = mac->receive(encoded_data, encoded_size, mac->user_data))) - { - WLog_ERR(TAG, "mac->receive failed with error %"PRIu32"", error); - SetLastError(ERROR_INTERNAL_ERROR); - return; - } - + if (error) + { + WLog_ERR(TAG, "mac->receive failed with error %"PRIu32"", error); + SetLastError(ERROR_INTERNAL_ERROR); + } } -static UINT audin_mac_close(IAudinDevice *device) +static UINT audin_mac_close(IAudinDevice* device) { - UINT errCode = CHANNEL_RC_OK; - char errString[1024]; - OSStatus devStat; - AudinMacDevice *mac = (AudinMacDevice*)device; + UINT errCode = CHANNEL_RC_OK; + char errString[1024]; + OSStatus devStat; + AudinMacDevice* mac = (AudinMacDevice*)device; - if (device == NULL) - return ERROR_INVALID_PARAMETER; + if (device == NULL) + return ERROR_INVALID_PARAMETER; - if (mac->isOpen) - { - devStat = AudioQueueStop(mac->audioQueue, true); - if (devStat != 0) - { - errCode = GetLastError(); - WLog_ERR(TAG, "AudioQueueStop failed with %s [%"PRIu32"]", - winpr_strerror(errCode, errString, sizeof(errString)), errCode); - } - mac->isOpen = false; - } + if (mac->isOpen) + { + devStat = AudioQueueStop(mac->audioQueue, true); - if (mac->audioQueue) - { - devStat = AudioQueueDispose(mac->audioQueue, true); - if (devStat != 0) - { - errCode = GetLastError(); - WLog_ERR(TAG, "AudioQueueDispose failed with %s [%"PRIu32"]", - winpr_strerror(errCode, errString, sizeof(errString)), errCode); - } + if (devStat != 0) + { + errCode = GetLastError(); + WLog_ERR(TAG, "AudioQueueStop failed with %s [%"PRIu32"]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + } - mac->audioQueue = NULL; - } + mac->isOpen = false; + } - mac->receive = NULL; - mac->user_data = NULL; + if (mac->audioQueue) + { + devStat = AudioQueueDispose(mac->audioQueue, true); - return errCode; + if (devStat != 0) + { + errCode = GetLastError(); + WLog_ERR(TAG, "AudioQueueDispose failed with %s [%"PRIu32"]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + } + + mac->audioQueue = NULL; + } + + mac->receive = NULL; + mac->user_data = NULL; + return errCode; } -static UINT audin_mac_open(IAudinDevice *device, AudinReceive receive, void *user_data) { - AudinMacDevice *mac = (AudinMacDevice*)device; - DWORD errCode; - char errString[1024]; - OSStatus devStat; - size_t index; +static UINT audin_mac_open(IAudinDevice* device, AudinReceive receive, void* user_data) +{ + AudinMacDevice* mac = (AudinMacDevice*)device; + DWORD errCode; + char errString[1024]; + OSStatus devStat; + size_t index; + mac->receive = receive; + mac->user_data = user_data; + devStat = AudioQueueNewInput(&(mac->audioFormat), mac_audio_queue_input_cb, + mac, NULL, kCFRunLoopCommonModes, 0, &(mac->audioQueue)); - mac->receive = receive; - mac->user_data = user_data; + if (devStat != 0) + { + errCode = GetLastError(); + WLog_ERR(TAG, "AudioQueueNewInput failed with %s [%"PRIu32"]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + goto err_out; + } - devStat = AudioQueueNewInput(&(mac->audioFormat), mac_audio_queue_input_cb, - mac, NULL, kCFRunLoopCommonModes, 0, &(mac->audioQueue)); - if (devStat != 0) - { - errCode = GetLastError(); - WLog_ERR(TAG, "AudioQueueNewInput failed with %s [%"PRIu32"]", - winpr_strerror(errCode, errString, sizeof(errString)), errCode); - goto err_out; - } + for (index = 0; index < MAC_AUDIO_QUEUE_NUM_BUFFERS; index++) + { + devStat = AudioQueueAllocateBuffer(mac->audioQueue, + mac->FramesPerPacket * 2 * mac->format.nChannels, + &mac->audioBuffers[index]); - for (index = 0; index < MAC_AUDIO_QUEUE_NUM_BUFFERS; index++) - { - devStat = AudioQueueAllocateBuffer(mac->audioQueue, MAC_AUDIO_QUEUE_BUFFER_SIZE, - &mac->audioBuffers[index]); - if (devStat != 0) - { - errCode = GetLastError(); - WLog_ERR(TAG, "AudioQueueAllocateBuffer failed with %s [%"PRIu32"]", - winpr_strerror(errCode, errString, sizeof(errString)), errCode); - goto err_out; - } + if (devStat != 0) + { + errCode = GetLastError(); + WLog_ERR(TAG, "AudioQueueAllocateBuffer failed with %s [%"PRIu32"]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + goto err_out; + } - devStat = AudioQueueEnqueueBuffer(mac->audioQueue, - mac->audioBuffers[index], - 0, - NULL); - if (devStat != 0) - { - errCode = GetLastError(); - WLog_ERR(TAG, "AudioQueueEnqueueBuffer failed with %s [%"PRIu32"]", - winpr_strerror(errCode, errString, sizeof(errString)), errCode); - goto err_out; - } - } + devStat = AudioQueueEnqueueBuffer(mac->audioQueue, + mac->audioBuffers[index], + 0, + NULL); - freerdp_dsp_context_reset_adpcm(mac->dsp_context); + if (devStat != 0) + { + errCode = GetLastError(); + WLog_ERR(TAG, "AudioQueueEnqueueBuffer failed with %s [%"PRIu32"]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + goto err_out; + } + } - devStat = AudioQueueStart(mac->audioQueue, NULL); - if (devStat != 0) - { - errCode = GetLastError(); - WLog_ERR(TAG, "AudioQueueStart failed with %s [%"PRIu32"]", - winpr_strerror(errCode, errString, sizeof(errString)), errCode); - goto err_out; - } - mac->isOpen = true; + devStat = AudioQueueStart(mac->audioQueue, NULL); - return CHANNEL_RC_OK; + if (devStat != 0) + { + errCode = GetLastError(); + WLog_ERR(TAG, "AudioQueueStart failed with %s [%"PRIu32"]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + goto err_out; + } + mac->isOpen = true; + return CHANNEL_RC_OK; err_out: - audin_mac_close(device); - return CHANNEL_RC_INITIALIZATION_ERROR; + audin_mac_close(device); + return CHANNEL_RC_INITIALIZATION_ERROR; } static UINT audin_mac_free(IAudinDevice* device) { - AudinMacDevice *mac = (AudinMacDevice*)device; + AudinMacDevice* mac = (AudinMacDevice*)device; + int error; - int error; + if (device == NULL) + return ERROR_INVALID_PARAMETER; - if (device == NULL) - return ERROR_INVALID_PARAMETER; + if ((error = audin_mac_close(device))) + { + WLog_ERR(TAG, "audin_oss_close failed with error code %d!", error); + } - if ((error = audin_mac_close(device))) - { - WLog_ERR(TAG, "audin_oss_close failed with error code %d!", error); - } - freerdp_dsp_context_free(mac->dsp_context); - free(mac); - - return CHANNEL_RC_OK; + free(mac); + return CHANNEL_RC_OK; } static COMMAND_LINE_ARGUMENT_A audin_mac_args[] = { - { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "audio device name" }, - { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } + { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "audio device name" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; -static UINT audin_mac_parse_addin_args(AudinMacDevice *device, ADDIN_ARGV *args) +static UINT audin_mac_parse_addin_args(AudinMacDevice* device, ADDIN_ARGV* args) { - DWORD errCode; - char errString[1024]; - int status; - char* str_num, *eptr; - DWORD flags; - COMMAND_LINE_ARGUMENT_A* arg; - AudinMacDevice* mac = (AudinMacDevice*)device; + DWORD errCode; + char errString[1024]; + int status; + char* str_num, *eptr; + DWORD flags; + COMMAND_LINE_ARGUMENT_A* arg; + AudinMacDevice* mac = (AudinMacDevice*)device; - if (args->argc == 1) - return CHANNEL_RC_OK; + if (args->argc == 1) + return CHANNEL_RC_OK; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, (const char**)args->argv, audin_mac_args, flags, mac, NULL, NULL); + flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = CommandLineParseArgumentsA(args->argc, args->argv, audin_mac_args, flags, + mac, NULL, NULL); - if (status < 0) - return ERROR_INVALID_PARAMETER; + if (status < 0) + return ERROR_INVALID_PARAMETER; - arg = audin_mac_args; + arg = audin_mac_args; - do - { - if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) - continue; + do + { + if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) + continue; - CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dev") - { - str_num = _strdup(arg->Value); - if (!str_num) - { - errCode = GetLastError(); - WLog_ERR(TAG, "_strdup failed with %s [%d]", - winpr_strerror(errCode, errString, sizeof(errString)), errCode); - return CHANNEL_RC_NO_MEMORY; - } - mac->dev_unit = strtol(str_num, &eptr, 10); + CommandLineSwitchStart(arg) + CommandLineSwitchCase(arg, "dev") + { + str_num = _strdup(arg->Value); - if (mac->dev_unit < 0 || *eptr != '\0') - mac->dev_unit = -1; + if (!str_num) + { + errCode = GetLastError(); + WLog_ERR(TAG, "_strdup failed with %s [%d]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + return CHANNEL_RC_NO_MEMORY; + } - free(str_num); - } - CommandLineSwitchEnd(arg) - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + mac->dev_unit = strtol(str_num, &eptr, 10); - return CHANNEL_RC_OK; + if (mac->dev_unit < 0 || *eptr != '\0') + mac->dev_unit = -1; + + free(str_num); + } + CommandLineSwitchEnd(arg) + } + while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + + return CHANNEL_RC_OK; } #ifdef BUILTIN_CHANNELS @@ -411,56 +372,44 @@ static UINT audin_mac_parse_addin_args(AudinMacDevice *device, ADDIN_ARGV *args) UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints) { - DWORD errCode; - char errString[1024]; - ADDIN_ARGV *args; - AudinMacDevice *mac; - UINT error; + DWORD errCode; + char errString[1024]; + ADDIN_ARGV* args; + AudinMacDevice* mac; + UINT error; + mac = (AudinMacDevice*)calloc(1, sizeof(AudinMacDevice)); - mac = (AudinMacDevice*)calloc(1, sizeof(AudinMacDevice)); - if (!mac) - { - errCode = GetLastError(); - WLog_ERR(TAG, "calloc failed with %s [%"PRIu32"]", - winpr_strerror(errCode, errString, sizeof(errString)), errCode); - return CHANNEL_RC_NO_MEMORY; - } + if (!mac) + { + errCode = GetLastError(); + WLog_ERR(TAG, "calloc failed with %s [%"PRIu32"]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + return CHANNEL_RC_NO_MEMORY; + } - mac->iface.Open = audin_mac_open; - mac->iface.FormatSupported = audin_mac_format_supported; - mac->iface.SetFormat = audin_mac_set_format; - mac->iface.Close = audin_mac_close; - mac->iface.Free = audin_mac_free; - mac->rdpcontext = pEntryPoints->rdpcontext; + mac->iface.Open = audin_mac_open; + mac->iface.FormatSupported = audin_mac_format_supported; + mac->iface.SetFormat = audin_mac_set_format; + mac->iface.Close = audin_mac_close; + mac->iface.Free = audin_mac_free; + mac->rdpcontext = pEntryPoints->rdpcontext; + mac->dev_unit = -1; + args = pEntryPoints->args; - mac->dev_unit = -1; - args = pEntryPoints->args; + if ((error = audin_mac_parse_addin_args(mac, args))) + { + WLog_ERR(TAG, "audin_mac_parse_addin_args failed with %"PRIu32"!", error); + goto error_out; + } - if ((error = audin_mac_parse_addin_args(mac, args))) - { - WLog_ERR(TAG, "audin_mac_parse_addin_args failed with %"PRIu32"!", error); - goto error_out; - } - - mac->dsp_context = freerdp_dsp_context_new(); - if (!mac->dsp_context) - { - WLog_ERR(TAG, "freerdp_dsp_context_new failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto error_out; - } - - if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) mac))) - { - WLog_ERR(TAG, "RegisterAudinDevice failed with error %"PRIu32"!", error); - goto error_out; - } - - return CHANNEL_RC_OK; + if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) mac))) + { + WLog_ERR(TAG, "RegisterAudinDevice failed with error %"PRIu32"!", error); + goto error_out; + } + return CHANNEL_RC_OK; error_out: - freerdp_dsp_context_free(mac->dsp_context); - free(mac); - return error; - + free(mac); + return error; } diff --git a/channels/audin/client/opensles/audin_opensl_es.c b/channels/audin/client/opensles/audin_opensl_es.c index 8a11aff..549edd0 100644 --- a/channels/audin/client/opensles/audin_opensl_es.c +++ b/channels/audin/client/opensles/audin_opensl_es.c @@ -29,12 +29,9 @@ #include #include -#include -#include #include #include -#include #include #include @@ -48,133 +45,38 @@ typedef struct _AudinOpenSLESDevice IAudinDevice iface; char* device_name; - OPENSL_STREAM *stream; + OPENSL_STREAM* stream; + AUDIO_FORMAT format; UINT32 frames_per_packet; - UINT32 rate; - UINT32 channels; UINT32 bytes_per_channel; - UINT32 format; - UINT32 block_size; - - FREERDP_DSP_CONTEXT* dsp_context; AudinReceive receive; - HANDLE thread; - HANDLE stopEvent; - void* user_data; rdpContext* rdpcontext; + wLog* log; } AudinOpenSLESDevice; -static DWORD WINAPI audin_opensles_thread_func(LPVOID arg) +static UINT audin_opensles_close(IAudinDevice* device); + +static void audin_receive(void* context, const void* data, size_t size) { - union - { - void *v; - short* s; - BYTE *b; - } buffer; - AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) arg; - const size_t raw_size = opensles->frames_per_packet * opensles->bytes_per_channel; - int rc = CHANNEL_RC_OK; - UINT error = CHANNEL_RC_OK; - DWORD status; + UINT error; + AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) context; - DEBUG_DVC("opensles=%p", (void*) opensles); - - assert(opensles); - assert(opensles->frames_per_packet > 0); - assert(opensles->dsp_context); - assert(opensles->stopEvent); - assert(opensles->stream); - - buffer.v = calloc(1, raw_size); - if (!buffer.v) + if (!opensles || !data) { - error = CHANNEL_RC_NO_MEMORY; - WLog_ERR(TAG, "calloc failed!"); - if (opensles->rdpcontext) - setChannelError(opensles->rdpcontext, CHANNEL_RC_NO_MEMORY, "audin_opensles_thread_func reported an error"); - goto out; + WLog_ERR(TAG, "[%s] Invalid arguments context=%p, data=%p", __FUNCTION__, opensles, data); + return; } - freerdp_dsp_context_reset_adpcm(opensles->dsp_context); - - while (1) - { - - status = WaitForSingleObject(opensles->stopEvent, 0); - - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); - break; - } - - if (status == WAIT_OBJECT_0) - break; - - size_t encoded_size; - void *encoded_data; - - rc = android_RecIn(opensles->stream, buffer.s, raw_size); - if (rc < 0) - { - WLog_ERR(TAG, "android_RecIn %d", rc); - continue; - } - - assert(rc == raw_size); - if (opensles->format == WAVE_FORMAT_ADPCM) - { - if (!opensles->dsp_context->encode_ms_adpcm(opensles->dsp_context, - buffer.b, rc, opensles->channels, opensles->block_size)) - { - error = ERROR_INTERNAL_ERROR; - break; - } - - encoded_data = opensles->dsp_context->adpcm_buffer; - encoded_size = opensles->dsp_context->adpcm_size; - } - else if (opensles->format == WAVE_FORMAT_DVI_ADPCM) - { - if (!opensles->dsp_context->encode_ima_adpcm(opensles->dsp_context, - buffer.b, rc, - opensles->channels, opensles->block_size)) - { - error = ERROR_INTERNAL_ERROR; - break; - } - - encoded_data = opensles->dsp_context->adpcm_buffer; - encoded_size = opensles->dsp_context->adpcm_size; - } - else - { - encoded_data = buffer.v; - encoded_size = rc; - } - - error = opensles->receive(encoded_data, encoded_size, opensles->user_data); - if (error) - break; - } - - free(buffer.v); -out: - DEBUG_DVC("thread shutdown."); + error = opensles->receive(&opensles->format, data, size, opensles->user_data); if (error && opensles->rdpcontext) - setChannelError(opensles->rdpcontext, error, "audin_opensles_thread_func reported an error"); - - ExitThread(error); - return error; + setChannelError(opensles->rdpcontext, error, "audin_receive reported an error"); } /** @@ -186,61 +88,49 @@ static UINT audin_opensles_free(IAudinDevice* device) { AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device; - DEBUG_DVC("device=%p", (void*) device); + if (!opensles) + return ERROR_INVALID_PARAMETER; + + WLog_Print(opensles->log, WLOG_DEBUG, "device=%p", (void*) device); /* The function may have been called out of order, * ignore duplicate requests. */ if (!opensles) return CHANNEL_RC_OK; - assert(opensles); - assert(opensles->dsp_context); - assert(!opensles->stream); - - freerdp_dsp_context_free(opensles->dsp_context); - free(opensles->device_name); - free(opensles); - return CHANNEL_RC_OK; } -static BOOL audin_opensles_format_supported(IAudinDevice* device, audinFormat* format) +static BOOL audin_opensles_format_supported(IAudinDevice* device, + const AUDIO_FORMAT* format) { -#ifdef WITH_DEBUG_DVC AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device; -#endif - - DEBUG_DVC("device=%p, format=%p", (void*) opensles, (void*) format); + if (!opensles || !format) + return FALSE; + + WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, format=%p", (void*) opensles, (void*) format); assert(format); switch (format->wFormatTag) { case WAVE_FORMAT_PCM: /* PCM */ if (format->cbSize == 0 && - (format->nSamplesPerSec <= 48000) && - (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && - (format->nChannels >= 1 && format->nChannels <= 2)) - { - return TRUE; - } - break; - /* TODO: Deactivated format, does not work, find out why */ -// case WAVE_FORMAT_ADPCM: /* IMA ADPCM */ - case WAVE_FORMAT_DVI_ADPCM: - if ((format->nSamplesPerSec <= 48000) && - (format->wBitsPerSample == 4) && - (format->nChannels == 1 || format->nChannels == 2)) + (format->nSamplesPerSec <= 48000) && + (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && + (format->nChannels >= 1 && format->nChannels <= 2)) { return TRUE; } + break; + default: - DEBUG_DVC("Encoding '%s' [0x%04X"PRIX16"] not supported", - rdpsnd_get_audio_tag_string(format->wFormatTag), - format->wFormatTag); + WLog_Print(opensles->log, WLOG_DEBUG, "Encoding '%s' [0x%04X"PRIX16"] not supported", + audio_format_get_tag_string(format->wFormatTag), + format->wFormatTag); break; } @@ -253,14 +143,15 @@ static BOOL audin_opensles_format_supported(IAudinDevice* device, audinFormat* f * @return 0 on success, otherwise a Win32 error code */ static UINT audin_opensles_set_format(IAudinDevice* device, - audinFormat* format, UINT32 FramesPerPacket) + const AUDIO_FORMAT* format, UINT32 FramesPerPacket) { - int bs; AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device; - DEBUG_DVC("device=%p, format=%p, FramesPerPacket=%"PRIu32"", - (void*) device, (void*) format, FramesPerPacket); + if (!opensles || !format) + return ERROR_INVALID_PARAMETER; + WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, format=%p, FramesPerPacket=%"PRIu32"", + (void*) device, (void*) format, FramesPerPacket); assert(format); /* The function may have been called out of order, ignore @@ -268,52 +159,42 @@ static UINT audin_opensles_set_format(IAudinDevice* device, if (!opensles) return CHANNEL_RC_OK; + opensles->format = *format; + switch (format->wFormatTag) { case WAVE_FORMAT_PCM: opensles->frames_per_packet = FramesPerPacket; + switch (format->wBitsPerSample) { case 4: opensles->bytes_per_channel = 1; break; + case 8: opensles->bytes_per_channel = 1; break; + case 16: opensles->bytes_per_channel = 2; break; + + default: + return ERROR_UNSUPPORTED_TYPE; } - break; - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - opensles->bytes_per_channel = 2; - bs = (format->nBlockAlign - 4 * format->nChannels) * 4; - - opensles->frames_per_packet = - (FramesPerPacket * format->nChannels * 2 / - bs + 1) * bs / (format->nChannels * 2); - break; - case WAVE_FORMAT_ALAW: - case WAVE_FORMAT_MULAW: - opensles->frames_per_packet = FramesPerPacket; + break; default: - WLog_ERR(TAG, "Encoding '%"PRIu16"' [%04"PRIX16"] not supported", - format->wFormatTag, - format->wFormatTag); + WLog_Print(opensles->log, WLOG_ERROR, "Encoding '%"PRIu16"' [%04"PRIX16"] not supported", + format->wFormatTag, + format->wFormatTag); return ERROR_UNSUPPORTED_TYPE; } - opensles->rate = format->nSamplesPerSec; - opensles->channels = format->nChannels; - - opensles->format = format->wFormatTag; - opensles->block_size = format->nBlockAlign; - - DEBUG_DVC("aligned frames_per_packet=%"PRIu32", block_size=%"PRIu32"", - opensles->frames_per_packet, opensles->block_size); + WLog_Print(opensles->log, WLOG_DEBUG, "frames_per_packet=%"PRIu32, + opensles->frames_per_packet); return CHANNEL_RC_OK; } @@ -323,51 +204,36 @@ static UINT audin_opensles_set_format(IAudinDevice* device, * @return 0 on success, otherwise a Win32 error code */ static UINT audin_opensles_open(IAudinDevice* device, AudinReceive receive, - void* user_data) + void* user_data) { AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device; - DEBUG_DVC("device=%p, receive=%p, user_data=%p", (void*) device, (void*) receive, (void*) user_data); + if (!opensles || !receive || !user_data) + return ERROR_INVALID_PARAMETER; - assert(opensles); + WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, receive=%p, user_data=%p", (void*) device, + (void*) receive, + (void*) user_data); - /* The function may have been called out of order, - * ignore duplicate open requests. */ - if(opensles->stream) - return CHANNEL_RC_OK; + if (opensles->stream) + goto error_out; - if(!(opensles->stream = android_OpenRecDevice( - opensles->device_name, - opensles->rate, - opensles->channels, - opensles->frames_per_packet, - opensles->bytes_per_channel * 8))) + if (!(opensles->stream = android_OpenRecDevice( + opensles, audin_receive, + opensles->format.nSamplesPerSec, + opensles->format.nChannels, + opensles->frames_per_packet, + opensles->format.wBitsPerSample))) { - WLog_ERR(TAG, "android_OpenRecDevice failed!"); - return ERROR_INTERNAL_ERROR; + WLog_Print(opensles->log, WLOG_ERROR, "android_OpenRecDevice failed!"); + goto error_out; } opensles->receive = receive; opensles->user_data = user_data; - - if (!(opensles->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) - { - WLog_ERR(TAG, "CreateEvent failed!"); - goto error_out; - } - if (!(opensles->thread = CreateThread(NULL, 0, - audin_opensles_thread_func, - opensles, 0, NULL))) - { - WLog_ERR(TAG, "CreateThread failed!"); - goto error_out; - } return CHANNEL_RC_OK; error_out: - android_CloseRecDevice(opensles->stream); - opensles->stream = NULL; - CloseHandle(opensles->stopEvent); - opensles->stopEvent = NULL; + audin_opensles_close(opensles); return ERROR_INTERNAL_ERROR; } @@ -376,52 +242,27 @@ error_out: * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_opensles_close(IAudinDevice* device) +UINT audin_opensles_close(IAudinDevice* device) { - UINT error; AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device; - DEBUG_DVC("device=%p", (void*) device); - - assert(opensles); - - /* The function may have been called out of order, - * ignore duplicate requests. */ - if (!opensles->stopEvent) - { - WLog_ERR(TAG, "[ERROR] function called without matching open."); - return ERROR_REQUEST_OUT_OF_SEQUENCE; - } - - assert(opensles->stopEvent); - assert(opensles->thread); - assert(opensles->stream); - - SetEvent(opensles->stopEvent); - if (WaitForSingleObject(opensles->thread, INFINITE) == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); - return error; - } - CloseHandle(opensles->stopEvent); - CloseHandle(opensles->thread); + if (!opensles) + return ERROR_INVALID_PARAMETER; + WLog_Print(opensles->log, WLOG_DEBUG, "device=%p", (void*) device); android_CloseRecDevice(opensles->stream); - - opensles->stopEvent = NULL; - opensles->thread = NULL; opensles->receive = NULL; opensles->user_data = NULL; opensles->stream = NULL; - return CHANNEL_RC_OK; } static COMMAND_LINE_ARGUMENT_A audin_opensles_args[] = { - { "dev", COMMAND_LINE_VALUE_REQUIRED, "", - NULL, NULL, -1, NULL, "audio device name" }, + { + "dev", COMMAND_LINE_VALUE_REQUIRED, "", + NULL, NULL, -1, NULL, "audio device name" + }, { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; @@ -431,19 +272,17 @@ static COMMAND_LINE_ARGUMENT_A audin_opensles_args[] = * @return 0 on success, otherwise a Win32 error code */ static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device, - ADDIN_ARGV* args) + ADDIN_ARGV* args) { UINT status; DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device; - - DEBUG_DVC("device=%p, args=%p", (void*) device, (void*) args); - + WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, args=%p", (void*) device, (void*) args); flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = CommandLineParseArgumentsA(args->argc, args->argv, + audin_opensles_args, flags, opensles, NULL, NULL); - status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, - audin_opensles_args, flags, opensles, NULL, NULL); if (status < 0) return status; @@ -455,17 +294,16 @@ static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device, continue; CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dev") { opensles->device_name = _strdup(arg->Value); + if (!opensles->device_name) { - WLog_ERR(TAG, "_strdup failed!"); + WLog_Print(opensles->log, WLOG_ERROR, "_strdup failed!"); return CHANNEL_RC_NO_MEMORY; } } - CommandLineSwitchEnd(arg) } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); @@ -487,53 +325,43 @@ static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device, * @return 0 on success, otherwise a Win32 error code */ UINT freerdp_audin_client_subsystem_entry( - PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints) + PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints) { ADDIN_ARGV* args; AudinOpenSLESDevice* opensles; UINT error; - - DEBUG_DVC("pEntryPoints=%p", (void*) pEntryPoints); - opensles = (AudinOpenSLESDevice*) calloc(1, sizeof(AudinOpenSLESDevice)); + if (!opensles) { WLog_ERR(TAG, "calloc failed!"); return CHANNEL_RC_NO_MEMORY; } + opensles->log = WLog_Get(TAG); opensles->iface.Open = audin_opensles_open; opensles->iface.FormatSupported = audin_opensles_format_supported; opensles->iface.SetFormat = audin_opensles_set_format; opensles->iface.Close = audin_opensles_close; opensles->iface.Free = audin_opensles_free; opensles->rdpcontext = pEntryPoints->rdpcontext; - args = pEntryPoints->args; if ((error = audin_opensles_parse_addin_args(opensles, args))) { - WLog_ERR(TAG, "audin_opensles_parse_addin_args failed with errorcode %"PRIu32"!", error); - goto error_out; - } - - opensles->dsp_context = freerdp_dsp_context_new(); - if (!opensles->dsp_context) - { - WLog_ERR(TAG, "freerdp_dsp_context_new failed!"); - error = CHANNEL_RC_NO_MEMORY; + WLog_Print(opensles->log, WLOG_ERROR, + "audin_opensles_parse_addin_args failed with errorcode %"PRIu32"!", error); goto error_out; } if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) opensles))) { - WLog_ERR(TAG, "RegisterAudinDevice failed with error %"PRIu32"!", error); + WLog_Print(opensles->log, WLOG_ERROR, "RegisterAudinDevice failed with error %"PRIu32"!", error); goto error_out; } return CHANNEL_RC_OK; error_out: - freerdp_dsp_context_free(opensles->dsp_context); free(opensles); return error; } diff --git a/channels/audin/client/opensles/opensl_io.c b/channels/audin/client/opensles/opensl_io.c index d12662b..5e7fba6 100644 --- a/channels/audin/client/opensles/opensl_io.c +++ b/channels/audin/client/opensles/opensl_io.c @@ -34,6 +34,39 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define CONV16BIT 32768 #define CONVMYFLT (1./32768.) +typedef struct +{ + size_t size; + void* data; +} queue_element; + +struct opensl_stream +{ + // engine interfaces + SLObjectItf engineObject; + SLEngineItf engineEngine; + + // device interfaces + SLDeviceVolumeItf deviceVolume; + + // recorder interfaces + SLObjectItf recorderObject; + SLRecordItf recorderRecord; + SLAndroidSimpleBufferQueueItf recorderBufferQueue; + + unsigned int inchannels; + unsigned int sr; + unsigned int buffersize; + unsigned int bits_per_sample; + + queue_element* prep; + queue_element* next; + + void* context; + opensl_receive_t receive; +}; + + static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void* context); // creates the OpenSL ES audio engine @@ -42,27 +75,23 @@ static SLresult openSLCreateEngine(OPENSL_STREAM* p) SLresult result; // create engine result = slCreateEngine(&(p->engineObject), 0, NULL, 0, NULL, NULL); - DEBUG_DVC("engineObject=%p", (void*) p->engineObject); if (result != SL_RESULT_SUCCESS) goto engine_end; // realize the engine result = (*p->engineObject)->Realize(p->engineObject, SL_BOOLEAN_FALSE); - DEBUG_DVC("Realize=%"PRIu32"", result); if (result != SL_RESULT_SUCCESS) goto engine_end; // get the engine interface, which is needed in order to create other objects result = (*p->engineObject)->GetInterface(p->engineObject, SL_IID_ENGINE, &(p->engineEngine)); - DEBUG_DVC("engineEngine=%p", (void*) p->engineEngine); if (result != SL_RESULT_SUCCESS) goto engine_end; // get the volume interface - important, this is optional! result = (*p->engineObject)->GetInterface(p->engineObject, SL_IID_DEVICEVOLUME, &(p->deviceVolume)); - DEBUG_DVC("deviceVolume=%p", (void*) p->deviceVolume); if (result != SL_RESULT_SUCCESS) { @@ -180,14 +209,12 @@ static SLresult openSLRecOpen(OPENSL_STREAM* p) const SLboolean req[] = {SL_BOOLEAN_TRUE}; result = (*p->engineEngine)->CreateAudioRecorder(p->engineEngine, &(p->recorderObject), &audioSrc, &audioSnk, 1, id, req); - DEBUG_DVC("p->recorderObject=%p", (void*) p->recorderObject); assert(!result); if (SL_RESULT_SUCCESS != result) goto end_recopen; // realize the audio recorder result = (*p->recorderObject)->Realize(p->recorderObject, SL_BOOLEAN_FALSE); - DEBUG_DVC("Realize=%"PRIu32"", result); assert(!result); if (SL_RESULT_SUCCESS != result) goto end_recopen; @@ -195,7 +222,6 @@ static SLresult openSLRecOpen(OPENSL_STREAM* p) // get the record interface result = (*p->recorderObject)->GetInterface(p->recorderObject, SL_IID_RECORD, &(p->recorderRecord)); - DEBUG_DVC("p->recorderRecord=%p", (void*) p->recorderRecord); assert(!result); if (SL_RESULT_SUCCESS != result) goto end_recopen; @@ -204,7 +230,6 @@ static SLresult openSLRecOpen(OPENSL_STREAM* p) result = (*p->recorderObject)->GetInterface(p->recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &(p->recorderBufferQueue)); - DEBUG_DVC("p->recorderBufferQueue=%p", (void*) p->recorderBufferQueue); assert(!result); if (SL_RESULT_SUCCESS != result) goto end_recopen; @@ -212,7 +237,6 @@ static SLresult openSLRecOpen(OPENSL_STREAM* p) // register callback on the buffer queue result = (*p->recorderBufferQueue)->RegisterCallback(p->recorderBufferQueue, bqRecorderCallback, p); - DEBUG_DVC("p->recorderBufferQueue=%p", (void*) p->recorderBufferQueue); assert(!result); if (SL_RESULT_SUCCESS != result) @@ -227,8 +251,6 @@ static SLresult openSLRecOpen(OPENSL_STREAM* p) // close the OpenSL IO and destroy the audio engine static void openSLDestroyEngine(OPENSL_STREAM* p) { - DEBUG_DVC("p=%p", (void*) p); - // destroy audio recorder object, and invalidate all associated interfaces if (p->recorderObject != NULL) { @@ -247,76 +269,94 @@ static void openSLDestroyEngine(OPENSL_STREAM* p) } } +static queue_element* opensles_queue_element_new(size_t size) +{ + queue_element* q = calloc(1, sizeof(queue_element)); + + if (!q) + goto fail; + + q->size = size; + q->data = malloc(size); + + if (!q->data) + goto fail; + + return q; +fail: + free(q); + return NULL; +} + +static void opensles_queue_element_free(void* obj) +{ + queue_element* e = (queue_element*)obj; + + if (e) + free(e->data); + + free(e); +} // open the android audio device for input -OPENSL_STREAM* android_OpenRecDevice(char* name, int sr, int inchannels, +OPENSL_STREAM* android_OpenRecDevice(void* context, opensl_receive_t receive, + int sr, + int inchannels, int bufferframes, int bits_per_sample) { OPENSL_STREAM* p; + + if (!context || !receive) + return NULL; + p = (OPENSL_STREAM*) calloc(1, sizeof(OPENSL_STREAM)); if (!p) return NULL; + p->context = context; + p->receive = receive; p->inchannels = inchannels; p->sr = sr; - p->queue = Queue_New(TRUE, -1, -1); p->buffersize = bufferframes; p->bits_per_sample = bits_per_sample; if ((p->bits_per_sample != 8) && (p->bits_per_sample != 16)) - { - android_CloseRecDevice(p); - return NULL; - } + goto fail; if (openSLCreateEngine(p) != SL_RESULT_SUCCESS) - { - android_CloseRecDevice(p); - return NULL; - } + goto fail; if (openSLRecOpen(p) != SL_RESULT_SUCCESS) - { - android_CloseRecDevice(p); - return NULL; - } + goto fail; + /* Create receive buffers, prepare them and start recording */ + p->prep = opensles_queue_element_new(p->buffersize * p->bits_per_sample / 8); + p->next = opensles_queue_element_new(p->buffersize * p->bits_per_sample / 8); + + if (!p->prep || !p->next) + goto fail; + + (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, + p->next->data, p->next->size); + (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, + p->prep->data, p->prep->size); + (*p->recorderRecord)->SetRecordState(p->recorderRecord, + SL_RECORDSTATE_RECORDING); return p; +fail: + android_CloseRecDevice(p); + return NULL; } // close the android audio device void android_CloseRecDevice(OPENSL_STREAM* p) { - DEBUG_DVC("p=%p", (void*) p); - if (p == NULL) return; - if (p->queue) - { - while (Queue_Count(p->queue) > 0) - { - queue_element* e = Queue_Dequeue(p->queue); - free(e->data); - free(e); - } - - Queue_Free(p->queue); - } - - if (p->next) - { - free(p->next->data); - free(p->next); - } - - if (p->prep) - { - free(p->prep->data); - free(p->prep); - } - + opensles_queue_element_free(p->next); + opensles_queue_element_free(p->prep); openSLDestroyEngine(p); free(p); } @@ -324,87 +364,25 @@ void android_CloseRecDevice(OPENSL_STREAM* p) // this callback handler is called every time a buffer finishes recording static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void* context) { - queue_element* e; OPENSL_STREAM* p = (OPENSL_STREAM*) context; - DEBUG_DVC("p=%p", (void*) p); - assert(p); - assert(p->next); - assert(p->prep); - assert(p->queue); - e = calloc(1, sizeof(queue_element)); + queue_element* e; + + if (!p) + return; + + e = p->next; if (!e) return; - e->data = calloc(p->buffersize, p->bits_per_sample / 8); + if (!p->context || !p->receive) + WLog_WARN(TAG, "Missing receive callback=%p, context=%p", p->receive, p->context); + else + p->receive(p->context, e->data, e->size); - if (!e->data) - { - free(e); - return; - } - - e->size = p->buffersize * p->bits_per_sample / 8; - Queue_Enqueue(p->queue, p->next); p->next = p->prep; p->prep = e; (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, e->data, e->size); } -// gets a buffer of size samples from the device -int android_RecIn(OPENSL_STREAM* p, short* buffer, int size) -{ - queue_element* e; - int rc; - DWORD status; - assert(p); - assert(buffer); - assert(size > 0); - - /* Initial trigger for the queue. */ - if (!p->prep) - { - p->prep = calloc(1, sizeof(queue_element)); - p->prep->data = calloc(p->buffersize, p->bits_per_sample / 8); - p->prep->size = p->buffersize * p->bits_per_sample / 8; - p->next = calloc(1, sizeof(queue_element)); - p->next->data = calloc(p->buffersize, p->bits_per_sample / 8); - p->next->size = p->buffersize * p->bits_per_sample / 8; - (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, - p->next->data, p->next->size); - (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, - p->prep->data, p->prep->size); - (*p->recorderRecord)->SetRecordState(p->recorderRecord, - SL_RECORDSTATE_RECORDING); - } - - /* Wait for queue to be filled... */ - if (!Queue_Count(p->queue)) - { - status = WaitForSingleObject(p->queue->event, INFINITE); - - if (status == WAIT_FAILED) - { - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", GetLastError()); - return -1; - } - } - - e = Queue_Dequeue(p->queue); - - if (!e) - { - WLog_ERR(TAG, "[ERROR] got e=NULL from queue"); - return -1; - } - - rc = (e->size < size) ? e->size : size; - assert(size == e->size); - assert(p->buffersize * p->bits_per_sample / 8 == size); - memcpy(buffer, e->data, rc); - free(e->data); - free(e); - return rc; -} - diff --git a/channels/audin/client/opensles/opensl_io.h b/channels/audin/client/opensles/opensl_io.h index 259b55a..6a54b7c 100644 --- a/channels/audin/client/opensles/opensl_io.h +++ b/channels/audin/client/opensles/opensl_io.h @@ -33,9 +33,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include -#include - #include #include @@ -44,51 +41,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. extern "C" { #endif -typedef struct -{ - size_t size; - void* data; -} queue_element; +typedef struct opensl_stream OPENSL_STREAM; -typedef struct opensl_stream -{ - // engine interfaces - SLObjectItf engineObject; - SLEngineItf engineEngine; - - // device interfaces - SLDeviceVolumeItf deviceVolume; - - // recorder interfaces - SLObjectItf recorderObject; - SLRecordItf recorderRecord; - SLAndroidSimpleBufferQueueItf recorderBufferQueue; - - unsigned int inchannels; - unsigned int sr; - unsigned int buffersize; - unsigned int bits_per_sample; - - wQueue* queue; - queue_element* prep; - queue_element* next; -} OPENSL_STREAM; +typedef void (*opensl_receive_t)(void* context, const void* data, size_t size); /* Open the audio device with a given sampling rate (sr), input and output channels and IO buffer size in frames. Returns a handle to the OpenSL stream */ -FREERDP_LOCAL OPENSL_STREAM* android_OpenRecDevice(char* name, int sr, +FREERDP_LOCAL OPENSL_STREAM* android_OpenRecDevice(void* context, + opensl_receive_t receive, int sr, int inchannels, int bufferframes, int bits_per_sample); /* Close the audio device */ FREERDP_LOCAL void android_CloseRecDevice(OPENSL_STREAM* p); -/* -Read a buffer from the OpenSL stream *p, of size samples. Returns the number of samples read. -*/ -FREERDP_LOCAL int android_RecIn(OPENSL_STREAM* p, short* buffer, int size); + #ifdef __cplusplus }; #endif diff --git a/channels/audin/client/oss/audin_oss.c b/channels/audin/client/oss/audin_oss.c index fb72ea2..e1d73b2 100644 --- a/channels/audin/client/oss/audin_oss.c +++ b/channels/audin/client/oss/audin_oss.c @@ -47,7 +47,6 @@ #include #include -#include #include #include "audin_main.h" @@ -56,12 +55,10 @@ typedef struct _AudinOSSDevice { IAudinDevice iface; - FREERDP_DSP_CONTEXT* dsp_context; - HANDLE thread; HANDLE stopEvent; - audinFormat format; + AUDIO_FORMAT format; UINT32 FramesPerPacket; int dev_unit; @@ -76,7 +73,7 @@ typedef struct _AudinOSSDevice WLog_ERR(TAG, "%s: %i - %s\n", _text, _error, strerror(_error)); -static int audin_oss_get_format(audinFormat* format) +static int audin_oss_get_format(const AUDIO_FORMAT* format) { switch (format->wFormatTag) { @@ -94,25 +91,17 @@ static int audin_oss_get_format(audinFormat* format) case WAVE_FORMAT_ALAW: return AFMT_A_LAW; -#if 0 /* This does not work on my desktop. */ case WAVE_FORMAT_MULAW: return AFMT_MU_LAW; -#endif - - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - return AFMT_S16_LE; } return 0; } static BOOL audin_oss_format_supported(IAudinDevice* device, - audinFormat* format) + const AUDIO_FORMAT* format) { - int req_fmt = 0; - if (device == NULL || format == NULL) return FALSE; @@ -127,21 +116,14 @@ static BOOL audin_oss_format_supported(IAudinDevice* device, break; - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - if (format->nSamplesPerSec > 48000 || - format->wBitsPerSample != 4 || - (format->nChannels != 1 && format->nChannels != 2)) - return FALSE; + case WAVE_FORMAT_ALAW: + case WAVE_FORMAT_MULAW: + return TRUE; - break; + default: + return FALSE; } - req_fmt = audin_oss_get_format(format); - - if (req_fmt == 0) - return FALSE; - return TRUE; } @@ -150,7 +132,7 @@ static BOOL audin_oss_format_supported(IAudinDevice* device, * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_oss_set_format(IAudinDevice* device, audinFormat* format, +static UINT audin_oss_set_format(IAudinDevice* device, const AUDIO_FORMAT* format, UINT32 FramesPerPacket) { AudinOSSDevice* oss = (AudinOSSDevice*)device; @@ -159,17 +141,7 @@ static UINT audin_oss_set_format(IAudinDevice* device, audinFormat* format, return ERROR_INVALID_PARAMETER; oss->FramesPerPacket = FramesPerPacket; - CopyMemory(&(oss->format), format, sizeof(audinFormat)); - - switch (format->wFormatTag) - { - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - oss->FramesPerPacket *= 4; /* Compression ratio. */ - oss->format.wBitsPerSample *= 4; - break; - } - + oss->format = *format; return CHANNEL_RC_OK; } @@ -178,13 +150,14 @@ static DWORD WINAPI audin_oss_thread_func(LPVOID arg) char dev_name[PATH_MAX] = "/dev/dsp"; char mixer_name[PATH_MAX] = "/dev/mixer"; int pcm_handle = -1, mixer_handle; - BYTE* buffer = NULL, *encoded_data = NULL; - int tmp, buffer_size, encoded_size; + BYTE* buffer = NULL; + int tmp; + size_t buffer_size; AudinOSSDevice* oss = (AudinOSSDevice*)arg; UINT error = 0; DWORD status; - if (arg == NULL) + if (oss == NULL) { error = ERROR_INVALID_PARAMETER; goto err_out; @@ -271,8 +244,6 @@ static DWORD WINAPI audin_oss_thread_func(LPVOID arg) goto err_out; } - freerdp_dsp_context_reset_adpcm(oss->dsp_context); - while (1) { status = WaitForSingleObject(oss->stopEvent, 0); @@ -299,40 +270,7 @@ static DWORD WINAPI audin_oss_thread_func(LPVOID arg) if (tmp < buffer_size) /* Not enouth data. */ continue; - /* Process. */ - switch (oss->format.wFormatTag) - { - case WAVE_FORMAT_ADPCM: - if (!oss->dsp_context->encode_ms_adpcm(oss->dsp_context, - buffer, buffer_size, oss->format.nChannels, oss->format.nBlockAlign)) - { - error = ERROR_INTERNAL_ERROR; - goto err_out; - } - - encoded_data = oss->dsp_context->adpcm_buffer; - encoded_size = oss->dsp_context->adpcm_size; - break; - - case WAVE_FORMAT_DVI_ADPCM: - if (!oss->dsp_context->encode_ima_adpcm(oss->dsp_context, - buffer, buffer_size, oss->format.nChannels, oss->format.nBlockAlign)) - { - error = ERROR_INTERNAL_ERROR; - goto err_out; - } - - encoded_data = oss->dsp_context->adpcm_buffer; - encoded_size = oss->dsp_context->adpcm_size; - break; - - default: - encoded_data = buffer; - encoded_size = buffer_size; - break; - } - - if ((error = oss->receive(encoded_data, encoded_size, oss->user_data))) + if ((error = oss->receive(&oss->format, buffer, buffer_size, oss->user_data))) { WLog_ERR(TAG, "oss->receive failed with error %"PRIu32"", error); break; @@ -438,12 +376,11 @@ static UINT audin_oss_free(IAudinDevice* device) WLog_ERR(TAG, "audin_oss_close failed with error code %d!", error); } - freerdp_dsp_context_free(oss->dsp_context); free(oss); return CHANNEL_RC_OK; } -COMMAND_LINE_ARGUMENT_A audin_oss_args[] = +static COMMAND_LINE_ARGUMENT_A audin_oss_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "audio device name" }, { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } @@ -463,7 +400,7 @@ static UINT audin_oss_parse_addin_args(AudinOSSDevice* device, ADDIN_ARGV* args) AudinOSSDevice* oss = (AudinOSSDevice*)device; flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, (const char**)args->argv, + status = CommandLineParseArgumentsA(args->argc, args->argv, audin_oss_args, flags, oss, NULL, NULL); if (status < 0) @@ -552,15 +489,6 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS goto error_out; } - oss->dsp_context = freerdp_dsp_context_new(); - - if (!oss->dsp_context) - { - WLog_ERR(TAG, "freerdp_dsp_context_new failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto error_out; - } - if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) oss))) { @@ -570,7 +498,6 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS return CHANNEL_RC_OK; error_out: - freerdp_dsp_context_free(oss->dsp_context); free(oss); return error; } diff --git a/channels/audin/client/pulse/audin_pulse.c b/channels/audin/client/pulse/audin_pulse.c index e3b163e..d22de87 100644 --- a/channels/audin/client/pulse/audin_pulse.c +++ b/channels/audin/client/pulse/audin_pulse.c @@ -29,12 +29,13 @@ #include #include +#include #include #include #include -#include +#include #include #include "audin_main.h" @@ -49,19 +50,16 @@ typedef struct _AudinPulseDevice pa_context* context; pa_sample_spec sample_spec; pa_stream* stream; - int format; - int block_size; + AUDIO_FORMAT format; - FREERDP_DSP_CONTEXT* dsp_context; - - int bytes_per_frame; - BYTE* buffer; - int buffer_frames; + size_t bytes_per_frame; + size_t buffer_frames; AudinReceive receive; void* user_data; rdpContext* rdpcontext; + wLog* log; } AudinPulseDevice; static void audin_pulse_context_state_callback(pa_context* context, void* userdata) @@ -73,18 +71,18 @@ static void audin_pulse_context_state_callback(pa_context* context, void* userda switch (state) { case PA_CONTEXT_READY: - DEBUG_DVC("PA_CONTEXT_READY"); + WLog_Print(pulse->log, WLOG_DEBUG, "PA_CONTEXT_READY"); pa_threaded_mainloop_signal(pulse->mainloop, 0); break; case PA_CONTEXT_FAILED: case PA_CONTEXT_TERMINATED: - DEBUG_DVC("state %d", state); + WLog_Print(pulse->log, WLOG_DEBUG, "state %d", state); pa_threaded_mainloop_signal(pulse->mainloop, 0); break; default: - DEBUG_DVC("state %d", state); + WLog_Print(pulse->log, WLOG_DEBUG, "state %d", state); break; } } @@ -104,8 +102,8 @@ static UINT audin_pulse_connect(IAudinDevice* device) if (pa_context_connect(pulse->context, NULL, 0, NULL)) { - WLog_ERR(TAG, "pa_context_connect failed (%d)", - pa_context_errno(pulse->context)); + WLog_Print(pulse->log, WLOG_ERROR, "pa_context_connect failed (%d)", + pa_context_errno(pulse->context)); return ERROR_INTERNAL_ERROR; } @@ -114,8 +112,8 @@ static UINT audin_pulse_connect(IAudinDevice* device) if (pa_threaded_mainloop_start(pulse->mainloop) < 0) { pa_threaded_mainloop_unlock(pulse->mainloop); - WLog_ERR(TAG, "pa_threaded_mainloop_start failed (%d)", - pa_context_errno(pulse->context)); + WLog_Print(pulse->log, WLOG_ERROR, "pa_threaded_mainloop_start failed (%d)", + pa_context_errno(pulse->context)); return ERROR_INTERNAL_ERROR; } @@ -128,8 +126,8 @@ static UINT audin_pulse_connect(IAudinDevice* device) if (!PA_CONTEXT_IS_GOOD(state)) { - WLog_ERR(TAG, "bad context state (%d)", - pa_context_errno(pulse->context)); + WLog_Print(pulse->log, WLOG_ERROR, "bad context state (%d)", + pa_context_errno(pulse->context)); pa_context_disconnect(pulse->context); return ERROR_INVALID_STATE; } @@ -138,7 +136,7 @@ static UINT audin_pulse_connect(IAudinDevice* device) } pa_threaded_mainloop_unlock(pulse->mainloop); - DEBUG_DVC("connected"); + WLog_Print(pulse->log, WLOG_DEBUG, "connected"); return CHANNEL_RC_OK; } @@ -172,21 +170,23 @@ static UINT audin_pulse_free(IAudinDevice* device) pulse->mainloop = NULL; } - freerdp_dsp_context_free(pulse->dsp_context); free(pulse); return CHANNEL_RC_OK; } -static BOOL audin_pulse_format_supported(IAudinDevice* device, audinFormat* format) +static BOOL audin_pulse_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format) { AudinPulseDevice* pulse = (AudinPulseDevice*) device; + if (!pulse || !format) + return FALSE; + if (!pulse->context) return 0; switch (format->wFormatTag) { - case 1: /* PCM */ + case WAVE_FORMAT_PCM: if (format->cbSize == 0 && (format->nSamplesPerSec <= PA_RATE_MAX) && (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && @@ -197,8 +197,8 @@ static BOOL audin_pulse_format_supported(IAudinDevice* device, audinFormat* form break; - case 6: /* A-LAW */ - case 7: /* U-LAW */ + case WAVE_FORMAT_ALAW: /* A-LAW */ + case WAVE_FORMAT_MULAW: /* U-LAW */ if (format->cbSize == 0 && (format->nSamplesPerSec <= PA_RATE_MAX) && (format->wBitsPerSample == 8) && @@ -209,15 +209,8 @@ static BOOL audin_pulse_format_supported(IAudinDevice* device, audinFormat* form break; - case 0x11: /* IMA ADPCM */ - if ((format->nSamplesPerSec <= PA_RATE_MAX) && - (format->wBitsPerSample == 4) && - (format->nChannels == 1 || format->nChannels == 2)) - { - return TRUE; - } - - break; + default: + return FALSE; } return FALSE; @@ -228,27 +221,27 @@ static BOOL audin_pulse_format_supported(IAudinDevice* device, audinFormat* form * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_pulse_set_format(IAudinDevice* device, audinFormat* format, +static UINT audin_pulse_set_format(IAudinDevice* device, const AUDIO_FORMAT* format, UINT32 FramesPerPacket) { - int bs; pa_sample_spec sample_spec = { 0 }; AudinPulseDevice* pulse = (AudinPulseDevice*) device; + if (!pulse || !format) + return ERROR_INVALID_PARAMETER; + if (!pulse->context) return ERROR_INVALID_PARAMETER; if (FramesPerPacket > 0) - { pulse->frames_per_packet = FramesPerPacket; - } sample_spec.rate = format->nSamplesPerSec; sample_spec.channels = format->nChannels; switch (format->wFormatTag) { - case 1: /* PCM */ + case WAVE_FORMAT_PCM: /* PCM */ switch (format->wBitsPerSample) { case 8: @@ -258,31 +251,27 @@ static UINT audin_pulse_set_format(IAudinDevice* device, audinFormat* format, case 16: sample_spec.format = PA_SAMPLE_S16LE; break; + + default: + return ERROR_INTERNAL_ERROR; } break; - case 6: /* A-LAW */ + case WAVE_FORMAT_ALAW: /* A-LAW */ sample_spec.format = PA_SAMPLE_ALAW; break; - case 7: /* U-LAW */ + case WAVE_FORMAT_MULAW: /* U-LAW */ sample_spec.format = PA_SAMPLE_ULAW; break; - case 0x11: /* IMA ADPCM */ - sample_spec.format = PA_SAMPLE_S16LE; - bs = (format->nBlockAlign - 4 * format->nChannels) * 4; - pulse->frames_per_packet = (pulse->frames_per_packet * format->nChannels * 2 / - bs + 1) * bs / (format->nChannels * 2); - DEBUG_DVC("aligned FramesPerPacket=%"PRIu32"", - pulse->frames_per_packet); - break; + default: + return ERROR_INTERNAL_ERROR; } pulse->sample_spec = sample_spec; - pulse->format = format->wFormatTag; - pulse->block_size = format->nBlockAlign; + pulse->format = *format; return CHANNEL_RC_OK; } @@ -295,99 +284,33 @@ static void audin_pulse_stream_state_callback(pa_stream* stream, void* userdata) switch (state) { case PA_STREAM_READY: - DEBUG_DVC("PA_STREAM_READY"); + WLog_Print(pulse->log, WLOG_DEBUG, "PA_STREAM_READY"); pa_threaded_mainloop_signal(pulse->mainloop, 0); break; case PA_STREAM_FAILED: case PA_STREAM_TERMINATED: - DEBUG_DVC("state %d", state); + WLog_Print(pulse->log, WLOG_DEBUG, "state %d", state); pa_threaded_mainloop_signal(pulse->mainloop, 0); break; default: - DEBUG_DVC("state %d", state); + WLog_Print(pulse->log, WLOG_DEBUG, "state %d", state); break; } } static void audin_pulse_stream_request_callback(pa_stream* stream, size_t length, void* userdata) { - int frames; - int cframes; const void* data; - const BYTE* src; - int encoded_size; - BYTE* encoded_data; AudinPulseDevice* pulse = (AudinPulseDevice*) userdata; UINT error = CHANNEL_RC_OK; - - /* There is a race condition here where we may receive this callback - * before the buffer has been set up in the main code. It's probably - * possible to fix with additional locking, but it's easier just to - * ignore input until the buffer is ready. - */ - if (pulse->buffer == NULL) - { - /* WLog_ERR(TAG, "%s: ignoring input, pulse buffer not ready.\n", __func__); */ - return; - } - pa_stream_peek(stream, &data, &length); - frames = length / pulse->bytes_per_frame; - DEBUG_DVC("length %"PRIdz" frames %d", length, frames); - src = (const BYTE*) data; - - while (frames > 0) - { - cframes = pulse->frames_per_packet - pulse->buffer_frames; - - if (cframes > frames) - cframes = frames; - - memcpy(pulse->buffer + pulse->buffer_frames * pulse->bytes_per_frame, - src, cframes * pulse->bytes_per_frame); - pulse->buffer_frames += cframes; - - if (pulse->buffer_frames >= pulse->frames_per_packet) - { - if (pulse->format == 0x11) - { - if (!pulse->dsp_context->encode_ima_adpcm(pulse->dsp_context, - pulse->buffer, pulse->buffer_frames * pulse->bytes_per_frame, - pulse->sample_spec.channels, pulse->block_size)) - { - error = ERROR_INTERNAL_ERROR; - break; - } - - encoded_data = pulse->dsp_context->adpcm_buffer; - encoded_size = pulse->dsp_context->adpcm_size; - } - else - { - encoded_data = pulse->buffer; - encoded_size = pulse->buffer_frames * pulse->bytes_per_frame; - } - - DEBUG_DVC("encoded %d [%d] to %d [%X]", - pulse->buffer_frames, pulse->bytes_per_frame, encoded_size, - pulse->format); - error = pulse->receive(encoded_data, encoded_size, pulse->user_data); - pulse->buffer_frames = 0; - - if (!error) - break; - } - - src += cframes * pulse->bytes_per_frame; - frames -= cframes; - } - + error = IFCALLRESULT(CHANNEL_RC_OK, pulse->receive, &pulse->format, data, length, pulse->user_data); pa_stream_drop(stream); if (error && pulse->rdpcontext) - setChannelError(pulse->rdpcontext, error, "audin_oss_thread_func reported an error"); + setChannelError(pulse->rdpcontext, error, "audin_pulse_thread_func reported an error"); } @@ -400,6 +323,9 @@ static UINT audin_pulse_close(IAudinDevice* device) { AudinPulseDevice* pulse = (AudinPulseDevice*) device; + if (!pulse) + return ERROR_INVALID_PARAMETER; + if (pulse->stream) { pa_threaded_mainloop_lock(pulse->mainloop); @@ -411,14 +337,6 @@ static UINT audin_pulse_close(IAudinDevice* device) pulse->receive = NULL; pulse->user_data = NULL; - - if (pulse->buffer) - { - free(pulse->buffer); - pulse->buffer = NULL; - pulse->buffer_frames = 0; - } - return CHANNEL_RC_OK; } @@ -433,13 +351,15 @@ static UINT audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u pa_buffer_attr buffer_attr = { 0 }; AudinPulseDevice* pulse = (AudinPulseDevice*) device; + if (!pulse || !receive || !user_data) + return ERROR_INVALID_PARAMETER; + if (!pulse->context) return ERROR_INVALID_PARAMETER; if (!pulse->sample_spec.rate || pulse->stream) return ERROR_INVALID_PARAMETER; - pulse->buffer = NULL; pulse->receive = receive; pulse->user_data = user_data; pa_threaded_mainloop_lock(pulse->mainloop); @@ -449,8 +369,8 @@ static UINT audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u if (!pulse->stream) { pa_threaded_mainloop_unlock(pulse->mainloop); - DEBUG_DVC("pa_stream_new failed (%d)", - pa_context_errno(pulse->context)); + WLog_Print(pulse->log, WLOG_DEBUG, "pa_stream_new failed (%d)", + pa_context_errno(pulse->context)); return pa_context_errno(pulse->context); } @@ -464,15 +384,19 @@ static UINT audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u buffer_attr.prebuf = (UINT32) - 1; buffer_attr.minreq = (UINT32) - 1; /* 500ms latency */ - buffer_attr.fragsize = pa_usec_to_bytes(500000, &pulse->sample_spec); + buffer_attr.fragsize = pulse->bytes_per_frame * pulse->frames_per_packet; + + if (buffer_attr.fragsize % pulse->format.nBlockAlign) + buffer_attr.fragsize += pulse->format.nBlockAlign - buffer_attr.fragsize % + pulse->format.nBlockAlign; if (pa_stream_connect_record(pulse->stream, pulse->device_name, &buffer_attr, PA_STREAM_ADJUST_LATENCY) < 0) { pa_threaded_mainloop_unlock(pulse->mainloop); - WLog_ERR(TAG, "pa_stream_connect_playback failed (%d)", - pa_context_errno(pulse->context)); + WLog_Print(pulse->log, WLOG_ERROR, "pa_stream_connect_playback failed (%d)", + pa_context_errno(pulse->context)); return pa_context_errno(pulse->context); } @@ -486,8 +410,8 @@ static UINT audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u if (!PA_STREAM_IS_GOOD(state)) { audin_pulse_close(device); - WLog_ERR(TAG, "bad stream state (%d)", - pa_context_errno(pulse->context)); + WLog_Print(pulse->log, WLOG_ERROR, "bad stream state (%d)", + pa_context_errno(pulse->context)); pa_threaded_mainloop_unlock(pulse->mainloop); return pa_context_errno(pulse->context); } @@ -496,17 +420,8 @@ static UINT audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u } pa_threaded_mainloop_unlock(pulse->mainloop); - freerdp_dsp_context_reset_adpcm(pulse->dsp_context); - pulse->buffer = calloc(pulse->frames_per_packet, pulse->bytes_per_frame); - - if (!pulse->buffer) - { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; - } - pulse->buffer_frames = 0; - DEBUG_DVC("connected"); + WLog_Print(pulse->log, WLOG_DEBUG, "connected"); return CHANNEL_RC_OK; } @@ -528,7 +443,7 @@ static UINT audin_pulse_parse_addin_args(AudinPulseDevice* device, ADDIN_ARGV* a COMMAND_LINE_ARGUMENT_A* arg; AudinPulseDevice* pulse = (AudinPulseDevice*) device; flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, audin_pulse_args, flags, + status = CommandLineParseArgumentsA(args->argc, args->argv, audin_pulse_args, flags, pulse, NULL, NULL); if (status < 0) @@ -548,7 +463,7 @@ static UINT audin_pulse_parse_addin_args(AudinPulseDevice* device, ADDIN_ARGV* a if (!pulse->device_name) { - WLog_ERR(TAG, "_strdup failed!"); + WLog_Print(pulse->log, WLOG_ERROR, "_strdup failed!"); return CHANNEL_RC_NO_MEMORY; } } @@ -583,6 +498,7 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn return CHANNEL_RC_NO_MEMORY; } + pulse->log = WLog_Get(TAG); pulse->iface.Open = audin_pulse_open; pulse->iface.FormatSupported = audin_pulse_format_supported; pulse->iface.SetFormat = audin_pulse_set_format; @@ -593,16 +509,8 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn if ((error = audin_pulse_parse_addin_args(pulse, args))) { - WLog_ERR(TAG, "audin_pulse_parse_addin_args failed with error %"PRIu32"!", error); - goto error_out; - } - - pulse->dsp_context = freerdp_dsp_context_new(); - - if (!pulse->dsp_context) - { - WLog_ERR(TAG, "freerdp_dsp_context_new failed!"); - error = CHANNEL_RC_NO_MEMORY; + WLog_Print(pulse->log, WLOG_ERROR, "audin_pulse_parse_addin_args failed with error %"PRIu32"!", + error); goto error_out; } @@ -610,7 +518,7 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn if (!pulse->mainloop) { - WLog_ERR(TAG, "pa_threaded_mainloop_new failed"); + WLog_Print(pulse->log, WLOG_ERROR, "pa_threaded_mainloop_new failed"); error = CHANNEL_RC_NO_MEMORY; goto error_out; } @@ -619,7 +527,7 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn if (!pulse->context) { - WLog_ERR(TAG, "pa_context_new failed"); + WLog_Print(pulse->log, WLOG_ERROR, "pa_context_new failed"); error = CHANNEL_RC_NO_MEMORY; goto error_out; } @@ -628,13 +536,13 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn if ((error = audin_pulse_connect((IAudinDevice*) pulse))) { - WLog_ERR(TAG, "audin_pulse_connect failed"); + WLog_Print(pulse->log, WLOG_ERROR, "audin_pulse_connect failed"); goto error_out; } if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) pulse))) { - WLog_ERR(TAG, "RegisterAudinDevice failed with error %"PRIu32"!", error); + WLog_Print(pulse->log, WLOG_ERROR, "RegisterAudinDevice failed with error %"PRIu32"!", error); goto error_out; } diff --git a/channels/audin/client/winmm/audin_winmm.c b/channels/audin/client/winmm/audin_winmm.c index aff631c..5e21005 100644 --- a/channels/audin/client/winmm/audin_winmm.c +++ b/channels/audin/client/winmm/audin_winmm.c @@ -47,41 +47,56 @@ typedef struct _AudinWinmmDevice HANDLE thread; HANDLE stopEvent; HWAVEIN hWaveIn; - PWAVEFORMATEX *ppwfx; + PWAVEFORMATEX* ppwfx; PWAVEFORMATEX pwfx_cur; UINT32 ppwfx_size; UINT32 cFormats; UINT32 frames_per_packet; rdpContext* rdpcontext; + wLog* log; } AudinWinmmDevice; static void CALLBACK waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD_PTR dwInstance, - DWORD_PTR dwParam1, DWORD_PTR dwParam2) + DWORD_PTR dwParam1, DWORD_PTR dwParam2) { AudinWinmmDevice* winmm = (AudinWinmmDevice*) dwInstance; PWAVEHDR pWaveHdr; UINT error = CHANNEL_RC_OK; MMRESULT mmResult; - switch(uMsg) + switch (uMsg) { case WIM_CLOSE: break; case WIM_DATA: - pWaveHdr = (WAVEHDR *)dwParam1; + pWaveHdr = (WAVEHDR*)dwParam1; + if (WHDR_DONE == (WHDR_DONE & pWaveHdr->dwFlags)) { if (pWaveHdr->dwBytesRecorded - && !(WaitForSingleObject(winmm->stopEvent, 0) == WAIT_OBJECT_0)) + && !(WaitForSingleObject(winmm->stopEvent, 0) == WAIT_OBJECT_0)) { - if ((error = winmm->receive(pWaveHdr->lpData, pWaveHdr->dwBytesRecorded, winmm->user_data))) + AUDIO_FORMAT format; + format.cbSize = winmm->pwfx_cur->cbSize; + format.nBlockAlign = winmm->pwfx_cur->nBlockAlign; + format.nAvgBytesPerSec = winmm->pwfx_cur->nAvgBytesPerSec; + format.nChannels = winmm->pwfx_cur->nChannels; + format.nSamplesPerSec = winmm->pwfx_cur->nSamplesPerSec; + format.wBitsPerSample = winmm->pwfx_cur->wBitsPerSample; + format.wFormatTag = winmm->pwfx_cur->wFormatTag; + + if ((error = winmm->receive(&format, pWaveHdr->lpData, pWaveHdr->dwBytesRecorded, + winmm->user_data))) break; + mmResult = waveInAddBuffer(hWaveIn, pWaveHdr, sizeof(WAVEHDR)); + if (mmResult != MMSYSERR_NOERROR) error = ERROR_INTERNAL_ERROR; } } + break; case WIM_OPEN: @@ -90,6 +105,7 @@ static void CALLBACK waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD_PTR dwInstance default: break; } + if (error && winmm->rdpcontext) setChannelError(winmm->rdpcontext, error, "waveInProc reported an error"); } @@ -97,7 +113,7 @@ static void CALLBACK waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD_PTR dwInstance static DWORD WINAPI audin_winmm_thread_func(LPVOID arg) { AudinWinmmDevice* winmm = (AudinWinmmDevice*) arg; - char *buffer; + char* buffer; int size, i; WAVEHDR waveHdr[4]; DWORD status; @@ -106,87 +122,113 @@ static DWORD WINAPI audin_winmm_thread_func(LPVOID arg) if (!winmm->hWaveIn) { if (MMSYSERR_NOERROR != waveInOpen(&winmm->hWaveIn, WAVE_MAPPER, winmm->pwfx_cur, - (DWORD_PTR)waveInProc, (DWORD_PTR)winmm, CALLBACK_FUNCTION)) + (DWORD_PTR)waveInProc, (DWORD_PTR)winmm, CALLBACK_FUNCTION)) { if (winmm->rdpcontext) - setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, "audin_winmm_thread_func reported an error"); - return 0; + setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, + "audin_winmm_thread_func reported an error"); + + return ERROR_INTERNAL_ERROR; } } - size = (winmm->pwfx_cur->wBitsPerSample * winmm->pwfx_cur->nChannels * winmm->frames_per_packet + 7) / 8; + size = (winmm->pwfx_cur->wBitsPerSample * winmm->pwfx_cur->nChannels * winmm->frames_per_packet + + 7) / 8; + for (i = 0; i < 4; i++) { - buffer = (char *) malloc(size); + buffer = (char*) malloc(size); + if (!buffer) return CHANNEL_RC_NO_MEMORY; + waveHdr[i].dwBufferLength = size; waveHdr[i].dwFlags = 0; waveHdr[i].lpData = buffer; - rc = waveInPrepareHeader(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i])); + if (MMSYSERR_NOERROR != rc) { - DEBUG_DVC("waveInPrepareHeader failed. %"PRIu32"", rc); + WLog_Print(winmm->log, WLOG_DEBUG, "waveInPrepareHeader failed. %"PRIu32"", rc); + if (winmm->rdpcontext) - setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, "audin_winmm_thread_func reported an error"); + setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, + "audin_winmm_thread_func reported an error"); } rc = waveInAddBuffer(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i])); + if (MMSYSERR_NOERROR != rc) { - DEBUG_DVC("waveInAddBuffer failed. %"PRIu32"", rc); + WLog_Print(winmm->log, WLOG_DEBUG, "waveInAddBuffer failed. %"PRIu32"", rc); + if (winmm->rdpcontext) - setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, "audin_winmm_thread_func reported an error"); + setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, + "audin_winmm_thread_func reported an error"); } } rc = waveInStart(winmm->hWaveIn); + if (MMSYSERR_NOERROR != rc) { - DEBUG_DVC("waveInStart failed. %"PRIu32"", rc); + WLog_Print(winmm->log, WLOG_DEBUG, "waveInStart failed. %"PRIu32"", rc); + if (winmm->rdpcontext) - setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, "audin_winmm_thread_func reported an error"); + setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, + "audin_winmm_thread_func reported an error"); } status = WaitForSingleObject(winmm->stopEvent, INFINITE); if (status == WAIT_FAILED) -{ - DEBUG_DVC("WaitForSingleObject failed."); + { + WLog_Print(winmm->log, WLOG_DEBUG, "WaitForSingleObject failed."); + if (winmm->rdpcontext) - setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, "audin_winmm_thread_func reported an error"); + setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, + "audin_winmm_thread_func reported an error"); } rc = waveInReset(winmm->hWaveIn); + if (MMSYSERR_NOERROR != rc) { - DEBUG_DVC("waveInReset failed. %"PRIu32"", rc); + WLog_Print(winmm->log, WLOG_DEBUG, "waveInReset failed. %"PRIu32"", rc); + if (winmm->rdpcontext) - setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, "audin_winmm_thread_func reported an error"); + setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, + "audin_winmm_thread_func reported an error"); } for (i = 0; i < 4; i++) { rc = waveInUnprepareHeader(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i])); + if (MMSYSERR_NOERROR != rc) { - DEBUG_DVC("waveInUnprepareHeader failed. %"PRIu32"", rc); + WLog_Print(winmm->log, WLOG_DEBUG, "waveInUnprepareHeader failed. %"PRIu32"", rc); + if (winmm->rdpcontext) - setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, "audin_winmm_thread_func reported an error"); + setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, + "audin_winmm_thread_func reported an error"); } + free(waveHdr[i].lpData); } rc = waveInClose(winmm->hWaveIn); + if (MMSYSERR_NOERROR != rc) { - DEBUG_DVC("waveInClose failed. %"PRIu32"", rc); - if (winmm->rdpcontext) - setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, "audin_winmm_thread_func reported an error"); - } - winmm->hWaveIn = NULL; + WLog_Print(winmm->log, WLOG_DEBUG, "waveInClose failed. %"PRIu32"", rc); + if (winmm->rdpcontext) + setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, + "audin_winmm_thread_func reported an error"); + } + + winmm->hWaveIn = NULL; return 0; } @@ -200,6 +242,9 @@ static UINT audin_winmm_free(IAudinDevice* device) UINT32 i; AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; + if (!winmm) + return ERROR_INVALID_PARAMETER; + for (i = 0; i < winmm->cFormats; i++) { free(winmm->ppwfx[i]); @@ -208,7 +253,6 @@ static UINT audin_winmm_free(IAudinDevice* device) free(winmm->ppwfx); free(winmm->device_name); free(winmm); - return CHANNEL_RC_OK; } @@ -219,29 +263,29 @@ static UINT audin_winmm_free(IAudinDevice* device) */ static UINT audin_winmm_close(IAudinDevice* device) { - DWORD status; - UINT error = CHANNEL_RC_OK; + DWORD status; + UINT error = CHANNEL_RC_OK; AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; - SetEvent(winmm->stopEvent); + if (!winmm) + return ERROR_INVALID_PARAMETER; + SetEvent(winmm->stopEvent); status = WaitForSingleObject(winmm->thread, INFINITE); - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); - return error; - } + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_Print(winmm->log, WLOG_ERROR, "WaitForSingleObject failed with error %"PRIu32"!", error); + return error; + } CloseHandle(winmm->thread); CloseHandle(winmm->stopEvent); - winmm->thread = NULL; winmm->stopEvent = NULL; winmm->receive = NULL; winmm->user_data = NULL; - return error; } @@ -250,62 +294,73 @@ static UINT audin_winmm_close(IAudinDevice* device) * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_winmm_set_format(IAudinDevice* device, audinFormat* format, UINT32 FramesPerPacket) +static UINT audin_winmm_set_format(IAudinDevice* device, const AUDIO_FORMAT* format, + UINT32 FramesPerPacket) { UINT32 i; AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; + if (!winmm || !format) + return ERROR_INVALID_PARAMETER; + winmm->frames_per_packet = FramesPerPacket; for (i = 0; i < winmm->cFormats; i++) { if (winmm->ppwfx[i]->wFormatTag == format->wFormatTag - && winmm->ppwfx[i]->nChannels == format->nChannels - && winmm->ppwfx[i]->wBitsPerSample == format->wBitsPerSample) + && winmm->ppwfx[i]->nChannels == format->nChannels + && winmm->ppwfx[i]->wBitsPerSample == format->wBitsPerSample) { winmm->pwfx_cur = winmm->ppwfx[i]; break; } } + return CHANNEL_RC_OK; } -static BOOL audin_winmm_format_supported(IAudinDevice* device, audinFormat* format) +static BOOL audin_winmm_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format) { AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; PWAVEFORMATEX pwfx; - BYTE *data; + BYTE* data; + + if (!winmm || !format) + return FALSE; pwfx = (PWAVEFORMATEX)malloc(sizeof(WAVEFORMATEX) + format->cbSize); + if (!pwfx) return FALSE; + pwfx->cbSize = format->cbSize; pwfx->wFormatTag = format->wFormatTag; pwfx->nChannels = format->nChannels; pwfx->nSamplesPerSec = format->nSamplesPerSec; pwfx->nBlockAlign = format->nBlockAlign; pwfx->wBitsPerSample = format->wBitsPerSample; - data = (BYTE *)pwfx + sizeof(WAVEFORMATEX); - + data = (BYTE*)pwfx + sizeof(WAVEFORMATEX); memcpy(data, format->data, format->cbSize); if (pwfx->wFormatTag == WAVE_FORMAT_PCM) { pwfx->nAvgBytesPerSec = pwfx->nSamplesPerSec * pwfx->nBlockAlign; + if (MMSYSERR_NOERROR == waveInOpen(NULL, WAVE_MAPPER, pwfx, 0, 0, WAVE_FORMAT_QUERY)) { if (winmm->cFormats >= winmm->ppwfx_size) { - PWAVEFORMATEX *tmp_ppwfx; + PWAVEFORMATEX* tmp_ppwfx; tmp_ppwfx = realloc(winmm->ppwfx, sizeof(PWAVEFORMATEX) * winmm->ppwfx_size * 2); + if (!tmp_ppwfx) return FALSE; winmm->ppwfx_size *= 2; winmm->ppwfx = tmp_ppwfx; } + winmm->ppwfx[winmm->cFormats++] = pwfx; - return TRUE; } } @@ -323,22 +378,27 @@ static UINT audin_winmm_open(IAudinDevice* device, AudinReceive receive, void* u { AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; + if (!winmm || !receive || !user_data) + return ERROR_INVALID_PARAMETER; + winmm->receive = receive; winmm->user_data = user_data; if (!(winmm->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) { - WLog_ERR(TAG, "CreateEvent failed!"); + WLog_Print(winmm->log, WLOG_ERROR, "CreateEvent failed!"); return ERROR_INTERNAL_ERROR; } - if (!(winmm->thread = CreateThread(NULL, 0, audin_winmm_thread_func, winmm, 0, NULL))) + if (!(winmm->thread = CreateThread(NULL, 0, + audin_winmm_thread_func, winmm, 0, NULL))) { - WLog_ERR(TAG, "CreateThread failed!"); + WLog_Print(winmm->log, WLOG_ERROR, "CreateThread failed!"); CloseHandle(winmm->stopEvent); winmm->stopEvent = NULL; return ERROR_INTERNAL_ERROR; } + return CHANNEL_RC_OK; } @@ -359,11 +419,9 @@ static UINT audin_winmm_parse_addin_args(AudinWinmmDevice* device, ADDIN_ARGV* a DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - - status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, audin_winmm_args, flags, winmm, NULL, NULL); - + status = CommandLineParseArgumentsA(args->argc, args->argv, audin_winmm_args, flags, + winmm, NULL, NULL); arg = audin_winmm_args; do @@ -372,17 +430,16 @@ static UINT audin_winmm_parse_addin_args(AudinWinmmDevice* device, ADDIN_ARGV* a continue; CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dev") { winmm->device_name = _strdup(arg->Value); + if (!winmm->device_name) { - WLog_ERR(TAG, "_strdup failed!"); + WLog_Print(winmm->log, WLOG_ERROR, "_strdup failed!"); return CHANNEL_RC_NO_MEMORY; } } - CommandLineSwitchEnd(arg) } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); @@ -406,35 +463,37 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn ADDIN_ARGV* args; AudinWinmmDevice* winmm; UINT error; - winmm = (AudinWinmmDevice*) calloc(1, sizeof(AudinWinmmDevice)); + if (!winmm) { WLog_ERR(TAG, "calloc failed!"); return CHANNEL_RC_NO_MEMORY; } + winmm->log = WLog_Get(TAG); winmm->iface.Open = audin_winmm_open; winmm->iface.FormatSupported = audin_winmm_format_supported; winmm->iface.SetFormat = audin_winmm_set_format; winmm->iface.Close = audin_winmm_close; winmm->iface.Free = audin_winmm_free; winmm->rdpcontext = pEntryPoints->rdpcontext; - args = pEntryPoints->args; if ((error = audin_winmm_parse_addin_args(winmm, args))) { - WLog_ERR(TAG, "audin_winmm_parse_addin_args failed with error %"PRIu32"!", error); + WLog_Print(winmm->log, WLOG_ERROR, "audin_winmm_parse_addin_args failed with error %"PRIu32"!", + error); goto error_out; } if (!winmm->device_name) { winmm->device_name = _strdup("default"); + if (!winmm->device_name) { - WLog_ERR(TAG, "_strdup failed!"); + WLog_Print(winmm->log, WLOG_ERROR, "_strdup failed!"); error = CHANNEL_RC_NO_MEMORY; goto error_out; } @@ -442,16 +501,17 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn winmm->ppwfx_size = 10; winmm->ppwfx = malloc(sizeof(PWAVEFORMATEX) * winmm->ppwfx_size); + if (!winmm->ppwfx) { - WLog_ERR(TAG, "malloc failed!"); + WLog_Print(winmm->log, WLOG_ERROR, "malloc failed!"); error = CHANNEL_RC_NO_MEMORY; goto error_out; } if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) winmm))) { - WLog_ERR(TAG, "RegisterAudinDevice failed with error %"PRIu32"!", error); + WLog_Print(winmm->log, WLOG_ERROR, "RegisterAudinDevice failed with error %"PRIu32"!", error); goto error_out; } diff --git a/channels/audin/server/audin.c b/channels/audin/server/audin.c index fc42fe1..f521667 100644 --- a/channels/audin/server/audin.c +++ b/channels/audin/server/audin.c @@ -70,7 +70,7 @@ typedef struct _audin_server * @return 0 on success, otherwise a Win32 error code */ static UINT audin_server_select_format(audin_server_context* context, - int client_format_index) + size_t client_format_index) { audin_server* audin = (audin_server*) context; @@ -81,7 +81,14 @@ static UINT audin_server_select_format(audin_server_context* context, return ERROR_INVALID_DATA; } - context->selected_client_format = client_format_index; + context->selected_client_format = (SSIZE_T)client_format_index; + + if (!freerdp_dsp_context_reset(audin->dsp_context, + &audin->context.client_formats[client_format_index])) + { + WLog_ERR(TAG, "Failed to reset dsp context format!"); + return ERROR_INTERNAL_ERROR; + } if (audin->opened) { @@ -147,8 +154,7 @@ static UINT audin_server_recv_version(audin_server* audin, wStream* s, */ static UINT audin_server_send_formats(audin_server* audin, wStream* s) { - int i; - UINT32 nAvgBytesPerSec; + size_t i; ULONG written; Stream_SetPosition(s, 0); Stream_Write_UINT8(s, MSG_SNDIN_FORMATS); @@ -159,35 +165,15 @@ static UINT audin_server_send_formats(audin_server* audin, wStream* s) for (i = 0; i < audin->context.num_server_formats; i++) { - nAvgBytesPerSec = audin->context.server_formats[i].nSamplesPerSec * - audin->context.server_formats[i].nChannels * - audin->context.server_formats[i].wBitsPerSample / 8; + AUDIO_FORMAT format = audin->context.server_formats[i]; + // TODO: Eliminate this + format.nAvgBytesPerSec = format.nSamplesPerSec * format.nChannels * format.wBitsPerSample / 8; - if (!Stream_EnsureRemainingCapacity(s, 18)) + if (!audio_format_write(s, &format)) { WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); return CHANNEL_RC_NO_MEMORY; } - - Stream_Write_UINT16(s, audin->context.server_formats[i].wFormatTag); - Stream_Write_UINT16(s, audin->context.server_formats[i].nChannels); - Stream_Write_UINT32(s, audin->context.server_formats[i].nSamplesPerSec); - Stream_Write_UINT32(s, nAvgBytesPerSec); - Stream_Write_UINT16(s, audin->context.server_formats[i].nBlockAlign); - Stream_Write_UINT16(s, audin->context.server_formats[i].wBitsPerSample); - Stream_Write_UINT16(s, audin->context.server_formats[i].cbSize); - - if (audin->context.server_formats[i].cbSize) - { - if (!Stream_EnsureRemainingCapacity(s, audin->context.server_formats[i].cbSize)) - { - WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - Stream_Write(s, audin->context.server_formats[i].data, - audin->context.server_formats[i].cbSize); - } } return WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), @@ -202,7 +188,7 @@ static UINT audin_server_send_formats(audin_server* audin, wStream* s) static UINT audin_server_recv_formats(audin_server* audin, wStream* s, UINT32 length) { - int i; + size_t i; UINT success = CHANNEL_RC_OK; if (length < 8) @@ -224,34 +210,24 @@ static UINT audin_server_recv_formats(audin_server* audin, wStream* s, return ERROR_INVALID_DATA; } - audin->context.client_formats = calloc(audin->context.num_client_formats, - sizeof(AUDIO_FORMAT)); + audin->context.client_formats = audio_formats_new(audin->context.num_client_formats); if (!audin->context.client_formats) return ERROR_NOT_ENOUGH_MEMORY; for (i = 0; i < audin->context.num_client_formats; i++) { - if (length < 18) + AUDIO_FORMAT* format = &audin->context.client_formats[i]; + + if (!audio_format_read(s, format)) { - free(audin->context.client_formats); + audio_formats_free(audin->context.client_formats, i); audin->context.client_formats = NULL; WLog_ERR(TAG, "expected length at least 18, but got %"PRIu32"", length); return ERROR_INVALID_DATA; } - Stream_Read_UINT16(s, audin->context.client_formats[i].wFormatTag); - Stream_Read_UINT16(s, audin->context.client_formats[i].nChannels); - Stream_Read_UINT32(s, audin->context.client_formats[i].nSamplesPerSec); - Stream_Seek_UINT32(s); /* nAvgBytesPerSec */ - Stream_Read_UINT16(s, audin->context.client_formats[i].nBlockAlign); - Stream_Read_UINT16(s, audin->context.client_formats[i].wBitsPerSample); - Stream_Read_UINT16(s, audin->context.client_formats[i].cbSize); - - if (audin->context.client_formats[i].cbSize > 0) - { - Stream_Seek(s, audin->context.client_formats[i].cbSize); - } + audio_format_print(WLog_Get(TAG), WLOG_DEBUG, format); } IFCALLRET(audin->context.Opening, success, &audin->context); @@ -339,10 +315,9 @@ static UINT audin_server_recv_data(audin_server* audin, wStream* s, AUDIO_FORMAT* format; int sbytes_per_sample; int sbytes_per_frame; - BYTE* src; - int size; int frames; - UINT success = CHANNEL_RC_OK; + wStream* out; + UINT success = ERROR_INTERNAL_ERROR; if (audin->context.selected_client_format < 0) { @@ -351,53 +326,32 @@ static UINT audin_server_recv_data(audin_server* audin, wStream* s, return ERROR_INVALID_DATA; } + out = Stream_New(NULL, 4096); + + if (!out) + return ERROR_OUTOFMEMORY; + format = &audin->context.client_formats[audin->context.selected_client_format]; - if (format->wFormatTag == WAVE_FORMAT_ADPCM) + if (freerdp_dsp_decode(audin->dsp_context, format, Stream_Pointer(s), length, out)) { - audin->dsp_context->decode_ms_adpcm(audin->dsp_context, - Stream_Pointer(s), length, format->nChannels, format->nBlockAlign); - size = audin->dsp_context->adpcm_size; - src = audin->dsp_context->adpcm_buffer; - sbytes_per_sample = 2; - sbytes_per_frame = format->nChannels * 2; - } - else if (format->wFormatTag == WAVE_FORMAT_DVI_ADPCM) - { - audin->dsp_context->decode_ima_adpcm(audin->dsp_context, - Stream_Pointer(s), length, format->nChannels, format->nBlockAlign); - size = audin->dsp_context->adpcm_size; - src = audin->dsp_context->adpcm_buffer; - sbytes_per_sample = 2; - sbytes_per_frame = format->nChannels * 2; - } - else - { - size = length; - src = Stream_Pointer(s); + AUDIO_FORMAT dformat = *format; + dformat.wFormatTag = WAVE_FORMAT_PCM; + dformat.wBitsPerSample = 16; + Stream_SealLength(out); + Stream_SetPosition(out, 0); sbytes_per_sample = format->wBitsPerSample / 8; sbytes_per_frame = format->nChannels * sbytes_per_sample; - } + frames = Stream_Length(out) / sbytes_per_frame; + IFCALLRET(audin->context.ReceiveSamples, success, &audin->context, &dformat, out, frames); - if (format->nSamplesPerSec == audin->context.dst_format.nSamplesPerSec - && format->nChannels == audin->context.dst_format.nChannels) - { - frames = size / sbytes_per_frame; + if (success) + WLog_ERR(TAG, "context.ReceiveSamples failed with error %"PRIu32"", success); } else - { - audin->dsp_context->resample(audin->dsp_context, src, sbytes_per_sample, - format->nChannels, format->nSamplesPerSec, size / sbytes_per_frame, - audin->context.dst_format.nChannels, audin->context.dst_format.nSamplesPerSec); - frames = audin->dsp_context->resampled_frames; - src = audin->dsp_context->resampled_buffer; - } - - IFCALLRET(audin->context.ReceiveSamples, success, &audin->context, src, frames); - - if (success) - WLog_ERR(TAG, "context.ReceiveSamples failed with error %"PRIu32"", success); + WLog_ERR(TAG, "freerdp_dsp_decode failed!"); + Stream_Free(out, TRUE); return success; } @@ -647,6 +601,16 @@ static BOOL audin_server_open(audin_server_context* context) return FALSE; } +static BOOL audin_server_is_open(audin_server_context* context) +{ + audin_server* audin = (audin_server*) context; + + if (!audin) + return FALSE; + + return audin->thread != NULL; +} + static BOOL audin_server_close(audin_server_context* context) { audin_server* audin = (audin_server*) context; @@ -693,8 +657,9 @@ audin_server_context* audin_server_context_new(HANDLE vcm) audin->context.frames_per_packet = 4096; audin->context.SelectFormat = audin_server_select_format; audin->context.Open = audin_server_open; + audin->context.IsOpen = audin_server_is_open; audin->context.Close = audin_server_close; - audin->dsp_context = freerdp_dsp_context_new(); + audin->dsp_context = freerdp_dsp_context_new(FALSE); if (!audin->dsp_context) { @@ -709,11 +674,13 @@ audin_server_context* audin_server_context_new(HANDLE vcm) void audin_server_context_free(audin_server_context* context) { audin_server* audin = (audin_server*) context; + + if (!audin) + return; + audin_server_close(context); - - if (audin->dsp_context) - freerdp_dsp_context_free(audin->dsp_context); - - free(audin->context.client_formats); + freerdp_dsp_context_free(audin->dsp_context); + audio_formats_free(audin->context.client_formats, audin->context.num_client_formats); + audio_formats_free(audin->context.server_formats, audin->context.num_server_formats); free(audin); } diff --git a/channels/client/addin.c b/channels/client/addin.c index 11e1fb8..86b9f43 100644 --- a/channels/client/addin.c +++ b/channels/client/addin.c @@ -87,9 +87,8 @@ extern const STATIC_ADDIN_TABLE CLIENT_STATIC_ADDIN_TABLE[]; FREERDP_ADDIN** freerdp_channels_list_client_static_addins(LPSTR pszName, LPSTR pszSubsystem, LPSTR pszType, DWORD dwFlags) { - int i, j; + size_t i, j; DWORD nAddins; - FREERDP_ADDIN* pAddin = NULL; FREERDP_ADDIN** ppAddins = NULL; STATIC_SUBSYSTEM_ENTRY* subsystems; nAddins = 0; @@ -105,7 +104,7 @@ FREERDP_ADDIN** freerdp_channels_list_client_static_addins(LPSTR pszName, LPSTR for (i = 0; CLIENT_STATIC_ADDIN_TABLE[i].name != NULL; i++) { - pAddin = (FREERDP_ADDIN*) calloc(1, sizeof(FREERDP_ADDIN)); + FREERDP_ADDIN* pAddin = (FREERDP_ADDIN*) calloc(1, sizeof(FREERDP_ADDIN)); if (!pAddin) { @@ -113,7 +112,7 @@ FREERDP_ADDIN** freerdp_channels_list_client_static_addins(LPSTR pszName, LPSTR goto error_out; } - strcpy(pAddin->cName, CLIENT_STATIC_ADDIN_TABLE[i].name); + sprintf_s(pAddin->cName, ARRAYSIZE(pAddin->cName), "%s", CLIENT_STATIC_ADDIN_TABLE[i].name); pAddin->dwFlags = FREERDP_ADDIN_CLIENT; pAddin->dwFlags |= FREERDP_ADDIN_STATIC; pAddin->dwFlags |= FREERDP_ADDIN_NAME; @@ -130,8 +129,8 @@ FREERDP_ADDIN** freerdp_channels_list_client_static_addins(LPSTR pszName, LPSTR goto error_out; } - strcpy(pAddin->cName, CLIENT_STATIC_ADDIN_TABLE[i].name); - strcpy(pAddin->cSubsystem, subsystems[j].name); + sprintf_s(pAddin->cName, ARRAYSIZE(pAddin->cName), "%s", CLIENT_STATIC_ADDIN_TABLE[i].name); + sprintf_s(pAddin->cSubsystem, ARRAYSIZE(pAddin->cSubsystem), "%s", subsystems[j].name); pAddin->dwFlags = FREERDP_ADDIN_CLIENT; pAddin->dwFlags |= FREERDP_ADDIN_STATIC; pAddin->dwFlags |= FREERDP_ADDIN_NAME; @@ -220,6 +219,7 @@ FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPSTR pszName, LPSTR pszSub if (!ppAddins) { + FindClose(hFind); WLog_ERR(TAG, "calloc failed!"); return NULL; } @@ -298,6 +298,7 @@ FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPSTR pszName, LPSTR pszSub ppAddins[nAddins] = NULL; return ppAddins; error_out: + FindClose(hFind); freerdp_channels_addin_list_free(ppAddins); return NULL; } diff --git a/channels/cliprdr/client/cliprdr_main.c b/channels/cliprdr/client/cliprdr_main.c index 6fe05dd..8ab0903 100644 --- a/channels/cliprdr/client/cliprdr_main.c +++ b/channels/cliprdr/client/cliprdr_main.c @@ -239,7 +239,7 @@ static UINT cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, Stream_Read_UINT16(s, capabilitySetType); /* capabilitySetType (2 bytes) */ Stream_Read_UINT16(s, lengthCapability); /* lengthCapability (2 bytes) */ - if (lengthCapability < 4 || Stream_GetRemainingLength(s) < lengthCapability-4) + if (lengthCapability < 4 || Stream_GetRemainingLength(s) < lengthCapability - 4) return ERROR_INVALID_DATA; switch (capabilitySetType) @@ -337,7 +337,6 @@ static UINT cliprdr_process_filecontents_request(cliprdrPlugin* cliprdr, request.msgFlags = flags; request.dataLen = length; request.haveClipDataId = FALSE; - Stream_Read_UINT32(s, request.streamId); /* streamId (4 bytes) */ Stream_Read_UINT32(s, request.listIndex); /* listIndex (4 bytes) */ Stream_Read_UINT32(s, request.dwFlags); /* dwFlags (4 bytes) */ @@ -633,6 +632,7 @@ static UINT cliprdr_temp_directory(CliprdrClientContext* context, } length = ConvertToUnicode(CP_UTF8, 0, tempDirectory->szTempDir, -1, &wszTempDir, 0); + if (length < 0) return ERROR_INTERNAL_ERROR; @@ -924,7 +924,6 @@ static UINT cliprdr_client_file_contents_request(CliprdrClientContext* context, WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFileContentsRequest: streamId: 0x%08"PRIX32"", fileContentsRequest->streamId); - return cliprdr_packet_send(cliprdr, s); } @@ -938,7 +937,6 @@ static UINT cliprdr_client_file_contents_response(CliprdrClientContext* context, { wStream* s; cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; - s = cliprdr_packet_new(CB_FILECONTENTS_RESPONSE, fileContentsResponse->msgFlags, 4 + fileContentsResponse->cbRequested); @@ -1045,7 +1043,6 @@ static VOID VCAPITYPE cliprdr_virtual_channel_open_event_ex(LPVOID lpUserParam, break; case CHANNEL_EVENT_WRITE_COMPLETE: - Stream_Free((wStream*) pData, TRUE); break; case CHANNEL_EVENT_USER: @@ -1131,7 +1128,8 @@ static UINT cliprdr_virtual_channel_event_connected(cliprdrPlugin* cliprdr, return ERROR_NOT_ENOUGH_MEMORY; } - if (!(cliprdr->thread = CreateThread(NULL, 0, cliprdr_virtual_channel_client_thread, (void*) cliprdr, + if (!(cliprdr->thread = CreateThread(NULL, 0, cliprdr_virtual_channel_client_thread, + (void*) cliprdr, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); @@ -1152,6 +1150,9 @@ static UINT cliprdr_virtual_channel_event_disconnected(cliprdrPlugin* cliprdr) { UINT rc; + if (cliprdr->OpenHandle == 0) + return CHANNEL_RC_OK; + if (MessageQueue_PostQuit(cliprdr->queue, 0) && (WaitForSingleObject(cliprdr->thread, INFINITE) == WAIT_FAILED)) { @@ -1258,7 +1259,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL; - strcpy(cliprdr->channelDef.name, "cliprdr"); + sprintf_s(cliprdr->channelDef.name, ARRAYSIZE(cliprdr->channelDef.name), "cliprdr"); pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*) pEntryPoints; if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) && diff --git a/channels/drdynvc/client/drdynvc_main.c b/channels/drdynvc/client/drdynvc_main.c index e7314ca..f27381b 100644 --- a/channels/drdynvc/client/drdynvc_main.c +++ b/channels/drdynvc/client/drdynvc_main.c @@ -639,8 +639,7 @@ static UINT dvcman_receive_channel_data(drdynvcPlugin* drdynvc, if (channel->dvc_data) { /* Fragmented data */ - if (Stream_GetPosition(channel->dvc_data) + dataSize > (UINT32) Stream_Capacity( - channel->dvc_data)) + if (Stream_GetPosition(channel->dvc_data) + dataSize > Stream_Capacity(channel->dvc_data)) { WLog_Print(drdynvc->log, WLOG_ERROR, "data exceeding declared length!"); Stream_Release(channel->dvc_data); @@ -648,7 +647,7 @@ static UINT dvcman_receive_channel_data(drdynvcPlugin* drdynvc, return ERROR_INVALID_DATA; } - Stream_Write(channel->dvc_data, Stream_Pointer(data), dataSize); + Stream_Copy(data, channel->dvc_data, dataSize); if (Stream_GetPosition(channel->dvc_data) >= channel->dvc_data_length) { @@ -713,9 +712,11 @@ static UINT drdynvc_send(drdynvcPlugin* drdynvc, wStream* s) { case CHANNEL_RC_OK: return CHANNEL_RC_OK; + case CHANNEL_RC_NOT_CONNECTED: Stream_Free(s, TRUE); return CHANNEL_RC_OK; + case CHANNEL_RC_BAD_CHANNEL_HANDLE: Stream_Free(s, TRUE); WLog_ERR(TAG, "VirtualChannelWriteEx failed with CHANNEL_RC_BAD_CHANNEL_HANDLE"); @@ -878,6 +879,9 @@ static UINT drdynvc_process_capability_request(drdynvcPlugin* drdynvc, int Sp, if (!drdynvc) return CHANNEL_RC_BAD_INIT_HANDLE; + if (Stream_GetRemainingLength(s) < 3) + return ERROR_INVALID_DATA; + WLog_Print(drdynvc->log, WLOG_TRACE, "capability_request Sp=%d cbChId=%d", Sp, cbChId); Stream_Seek(s, 1); /* pad */ Stream_Read_UINT16(s, drdynvc->version); @@ -887,6 +891,9 @@ static UINT drdynvc_process_capability_request(drdynvcPlugin* drdynvc, int Sp, */ if ((drdynvc->version == 2) || (drdynvc->version == 3)) { + if (Stream_GetRemainingLength(s) < 8) + return ERROR_INVALID_DATA; + Stream_Read_UINT16(s, drdynvc->PriorityCharge0); Stream_Read_UINT16(s, drdynvc->PriorityCharge1); Stream_Read_UINT16(s, drdynvc->PriorityCharge2); @@ -898,6 +905,21 @@ static UINT drdynvc_process_capability_request(drdynvcPlugin* drdynvc, int Sp, return status; } +static UINT32 drdynvc_cblen_to_bytes(int cbLen) +{ + switch (cbLen) + { + case 0: + return 1; + + case 1: + return 2; + + default: + return 4; + } +} + static UINT32 drdynvc_read_variable_uint(wStream* s, int cbLen) { UINT32 val; @@ -933,6 +955,8 @@ static UINT drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, UINT32 ChannelId; wStream* data_out; UINT channel_status; + char* name; + size_t length; if (!drdynvc) return CHANNEL_RC_BAD_CHANNEL_HANDLE; @@ -955,13 +979,20 @@ static UINT drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, drdynvc->state = DRDYNVC_STATE_READY; } + if (Stream_GetRemainingLength(s) < drdynvc_cblen_to_bytes(cbChId)) + return ERROR_INVALID_DATA; + ChannelId = drdynvc_read_variable_uint(s, cbChId); pos = Stream_GetPosition(s); + name = (char*)Stream_Pointer(s); + length = Stream_GetRemainingLength(s); + + if (strnlen(name, length) >= length) + return ERROR_INVALID_DATA; + WLog_Print(drdynvc->log, WLOG_DEBUG, "process_create_request: ChannelId=%"PRIu32" ChannelName=%s", - ChannelId, - Stream_Pointer(s)); - channel_status = dvcman_create_channel(drdynvc, drdynvc->channel_mgr, ChannelId, - (char*) Stream_Pointer(s)); + ChannelId, name); + channel_status = dvcman_create_channel(drdynvc, drdynvc->channel_mgr, ChannelId, name); data_out = Stream_New(NULL, pos + 4); if (!data_out) @@ -1022,6 +1053,10 @@ static UINT drdynvc_process_data_first(drdynvcPlugin* drdynvc, int Sp, UINT status; UINT32 Length; UINT32 ChannelId; + + if (Stream_GetRemainingLength(s) < drdynvc_cblen_to_bytes(cbChId) + drdynvc_cblen_to_bytes(Sp)) + return ERROR_INVALID_DATA; + ChannelId = drdynvc_read_variable_uint(s, cbChId); Length = drdynvc_read_variable_uint(s, Sp); WLog_Print(drdynvc->log, WLOG_DEBUG, @@ -1045,6 +1080,10 @@ static UINT drdynvc_process_data(drdynvcPlugin* drdynvc, int Sp, int cbChId, wStream* s) { UINT32 ChannelId; + + if (Stream_GetRemainingLength(s) < drdynvc_cblen_to_bytes(cbChId)) + return ERROR_INVALID_DATA; + ChannelId = drdynvc_read_variable_uint(s, cbChId); WLog_Print(drdynvc->log, WLOG_TRACE, "process_data: Sp=%d cbChId=%d, ChannelId=%"PRIu32"", Sp, cbChId, @@ -1064,6 +1103,10 @@ static UINT drdynvc_process_close_request(drdynvcPlugin* drdynvc, int Sp, UINT error; UINT32 ChannelId; wStream* data_out; + + if (Stream_GetRemainingLength(s) < drdynvc_cblen_to_bytes(cbChId)) + return ERROR_INVALID_DATA; + ChannelId = drdynvc_read_variable_uint(s, cbChId); WLog_Print(drdynvc->log, WLOG_DEBUG, "process_close_request: Sp=%d cbChId=%d, ChannelId=%"PRIu32"", Sp, @@ -1106,6 +1149,10 @@ static UINT drdynvc_order_recv(drdynvcPlugin* drdynvc, wStream* s) int Cmd; int Sp; int cbChId; + + if (Stream_GetRemainingLength(s) < 1) + return ERROR_INVALID_DATA; + Stream_Read_UINT8(s, value); Cmd = (value & 0xf0) >> 4; Sp = (value & 0x0c) >> 2; @@ -1164,7 +1211,7 @@ static UINT drdynvc_virtual_channel_event_data_received(drdynvcPlugin* drdynvc, return CHANNEL_RC_NO_MEMORY; } - if (!Stream_EnsureRemainingCapacity(data_in, (int) dataLength)) + if (!Stream_EnsureRemainingCapacity(data_in, dataLength)) { WLog_Print(drdynvc->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); Stream_Free(drdynvc->data_in, TRUE); @@ -1205,7 +1252,6 @@ static void VCAPITYPE drdynvc_virtual_channel_open_event_ex(LPVOID lpUserParam, if (!drdynvc || (drdynvc->OpenHandle != openHandle)) { WLog_ERR(TAG, "drdynvc_virtual_channel_open_event: error no match"); - Stream_Free((wStream*) pData, TRUE); return; } @@ -1220,7 +1266,6 @@ static void VCAPITYPE drdynvc_virtual_channel_open_event_ex(LPVOID lpUserParam, break; case CHANNEL_EVENT_WRITE_COMPLETE: - Stream_Free((wStream*) pData, TRUE); break; case CHANNEL_EVENT_USER: @@ -1380,7 +1425,8 @@ static UINT drdynvc_virtual_channel_event_connected(drdynvcPlugin* drdynvc, LPVO drdynvc->state = DRDYNVC_STATE_CAPABILITIES; - if (!(drdynvc->thread = CreateThread(NULL, 0, drdynvc_virtual_channel_client_thread, (void*) drdynvc, + if (!(drdynvc->thread = CreateThread(NULL, 0, drdynvc_virtual_channel_client_thread, + (void*) drdynvc, 0, NULL))) { error = ERROR_INTERNAL_ERROR; @@ -1401,6 +1447,9 @@ static UINT drdynvc_virtual_channel_event_disconnected(drdynvcPlugin* drdynvc) { UINT status; + if (drdynvc->OpenHandle == 0) + return CHANNEL_RC_OK; + if (!drdynvc) return CHANNEL_RC_BAD_CHANNEL_HANDLE; @@ -1611,7 +1660,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints, PVOI CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP; - strcpy(drdynvc->channelDef.name, "drdynvc"); + sprintf_s(drdynvc->channelDef.name, ARRAYSIZE(drdynvc->channelDef.name), "drdynvc"); drdynvc->state = DRDYNVC_STATE_INITIAL; pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*) pEntryPoints; diff --git a/channels/drive/client/drive_file.c b/channels/drive/client/drive_file.c index 253b588..f816695 100644 --- a/channels/drive/client/drive_file.c +++ b/channels/drive/client/drive_file.c @@ -53,8 +53,8 @@ static void drive_file_fix_path(WCHAR* path) { - int i; - int length; + size_t i; + size_t length; length = (int) _wcslen(path); for (i = 0; i < length; i++) @@ -332,11 +332,6 @@ DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 Pat return NULL; } - if (DesiredAccess & 0x1000L) - { - DesiredAccess = (DesiredAccess & ~0x1000L) | GENERIC_WRITE; - } - file->file_handle = INVALID_HANDLE_VALUE; file->find_handle = INVALID_HANDLE_VALUE; file->id = id; @@ -360,6 +355,7 @@ DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 Pat BOOL drive_file_free(DRIVE_FILE* file) { BOOL rc = FALSE; + if (!file) return FALSE; @@ -387,7 +383,6 @@ BOOL drive_file_free(DRIVE_FILE* file) } rc = TRUE; - fail: DEBUG_WSTR("Free %s", file->fullpath); free(file->fullpath); @@ -447,30 +442,14 @@ BOOL drive_file_write(DRIVE_FILE* file, BYTE* buffer, UINT32 Length) BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, wStream* output) { - WIN32_FIND_DATAW findFileData; - HANDLE hFind; + WIN32_FILE_ATTRIBUTE_DATA fileAttributes; DEBUG_WSTR("FindFirstFile %s", file->fullpath); if (!file || !output) return FALSE; - if ((hFind = FindFirstFileW(file->fullpath, &findFileData)) == INVALID_HANDLE_VALUE) - { -#ifdef WIN32 - ZeroMemory(&findFileData, sizeof(findFileData)); - findFileData.dwFileAttributes = GetFileAttributesW(file->fullpath); - - if (findFileData.dwFileAttributes == INVALID_FILE_ATTRIBUTES) - { - goto out_fail; - } - -#else + if (!GetFileAttributesExW(file->fullpath, GetFileExInfoStandard, &fileAttributes)) goto out_fail; -#endif - } - - FindClose(hFind); switch (FsInformationClass) { @@ -481,15 +460,15 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w goto out_fail; Stream_Write_UINT32(output, 36); /* Length */ - Stream_Write_UINT32(output, findFileData.ftCreationTime.dwLowDateTime); /* CreationTime */ - Stream_Write_UINT32(output, findFileData.ftCreationTime.dwHighDateTime); /* CreationTime */ - Stream_Write_UINT32(output, findFileData.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */ - Stream_Write_UINT32(output, findFileData.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */ - Stream_Write_UINT32(output, findFileData.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */ - Stream_Write_UINT32(output, findFileData.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */ - Stream_Write_UINT32(output, findFileData.ftLastWriteTime.dwLowDateTime); /* ChangeTime */ - Stream_Write_UINT32(output, findFileData.ftLastWriteTime.dwHighDateTime); /* ChangeTime */ - Stream_Write_UINT32(output, findFileData.dwFileAttributes); /* FileAttributes */ + Stream_Write_UINT32(output, fileAttributes.ftCreationTime.dwLowDateTime); /* CreationTime */ + Stream_Write_UINT32(output, fileAttributes.ftCreationTime.dwHighDateTime); /* CreationTime */ + Stream_Write_UINT32(output, fileAttributes.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */ + Stream_Write_UINT32(output, fileAttributes.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */ + Stream_Write_UINT32(output, fileAttributes.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */ + Stream_Write_UINT32(output, fileAttributes.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */ + Stream_Write_UINT32(output, fileAttributes.ftLastWriteTime.dwLowDateTime); /* ChangeTime */ + Stream_Write_UINT32(output, fileAttributes.ftLastWriteTime.dwHighDateTime); /* ChangeTime */ + Stream_Write_UINT32(output, fileAttributes.dwFileAttributes); /* FileAttributes */ /* Reserved(4), MUST NOT be added! */ break; @@ -500,13 +479,13 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w goto out_fail; Stream_Write_UINT32(output, 22); /* Length */ - Stream_Write_UINT32(output, findFileData.nFileSizeLow); /* AllocationSize */ - Stream_Write_UINT32(output, findFileData.nFileSizeHigh); /* AllocationSize */ - Stream_Write_UINT32(output, findFileData.nFileSizeLow); /* EndOfFile */ - Stream_Write_UINT32(output, findFileData.nFileSizeHigh); /* EndOfFile */ + Stream_Write_UINT32(output, fileAttributes.nFileSizeLow); /* AllocationSize */ + Stream_Write_UINT32(output, fileAttributes.nFileSizeHigh); /* AllocationSize */ + Stream_Write_UINT32(output, fileAttributes.nFileSizeLow); /* EndOfFile */ + Stream_Write_UINT32(output, fileAttributes.nFileSizeHigh); /* EndOfFile */ Stream_Write_UINT32(output, 0); /* NumberOfLinks */ Stream_Write_UINT8(output, file->delete_pending ? 1 : 0); /* DeletePending */ - Stream_Write_UINT8(output, findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? TRUE : + Stream_Write_UINT8(output, fileAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? TRUE : FALSE); /* Directory */ /* Reserved(2), MUST NOT be added! */ break; @@ -518,7 +497,7 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w goto out_fail; Stream_Write_UINT32(output, 8); /* Length */ - Stream_Write_UINT32(output, findFileData.dwFileAttributes); /* FileAttributes */ + Stream_Write_UINT32(output, fileAttributes.dwFileAttributes); /* FileAttributes */ Stream_Write_UINT32(output, 0); /* ReparseTag */ break; @@ -636,8 +615,6 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN return FALSE; } - liSize.QuadPart = size & 0xFFFFFFFF; - if (!SetFilePointerEx(file->file_handle, liSize, NULL, FILE_BEGIN)) { WLog_ERR(TAG, "Unable to truncate %s to %d (%"PRId32")", file->fullpath, size, GetLastError()); @@ -700,6 +677,7 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN fullpath = drive_file_combine_fullpath(file->basepath, (WCHAR*)Stream_Pointer(input), FileNameLength); + if (!fullpath) { WLog_ERR(TAG, "drive_file_combine_fullpath failed!"); diff --git a/channels/drive/client/drive_main.c b/channels/drive/client/drive_main.c index c78a8ec..df361c0 100644 --- a/channels/drive/client/drive_main.c +++ b/channels/drive/client/drive_main.c @@ -53,6 +53,7 @@ struct _DRIVE_DEVICE DEVICE device; WCHAR* path; + BOOL automount; UINT32 PathLength; wListDictionary* files; @@ -97,7 +98,7 @@ static DWORD drive_map_windows_err(DWORD fs_errno) case ERROR_NOT_READY: rc = STATUS_NO_SUCH_DEVICE; - break; + break; case ERROR_FILE_EXISTS: case ERROR_ALREADY_EXISTS: @@ -167,7 +168,7 @@ static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp) if (!drive || !irp || !irp->devman || !irp->Complete) return ERROR_INVALID_PARAMETER; - if (Stream_GetRemainingLength(irp->input) < 6*4+8) + if (Stream_GetRemainingLength(irp->input) < 6 * 4 + 8) return ERROR_INVALID_DATA; Stream_Read_UINT32(irp->input, DesiredAccess); @@ -177,6 +178,7 @@ static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp) Stream_Read_UINT32(irp->input, CreateDisposition); Stream_Read_UINT32(irp->input, CreateOptions); Stream_Read_UINT32(irp->input, PathLength); + if (Stream_GetRemainingLength(irp->input) < PathLength) return ERROR_INVALID_DATA; @@ -238,6 +240,7 @@ static UINT drive_process_irp_close(DRIVE_DEVICE* drive, IRP* irp) { void* key; DRIVE_FILE* file; + if (!drive || !irp || !irp->Complete || !irp->output) return ERROR_INVALID_PARAMETER; @@ -279,8 +282,8 @@ static UINT drive_process_irp_read(DRIVE_DEVICE* drive, IRP* irp) Stream_Read_UINT32(irp->input, Length); Stream_Read_UINT64(irp->input, Offset); - file = drive_get_file_by_id(drive, irp->FileId); + if (!file) { irp->IoStatus = STATUS_UNSUCCESSFUL; @@ -302,6 +305,7 @@ static UINT drive_process_irp_read(DRIVE_DEVICE* drive, IRP* irp) else { BYTE* buffer = Stream_Pointer(irp->output) + sizeof(UINT32); + if (!drive_file_read(file, buffer, &Length)) { irp->IoStatus = drive_map_windows_err(GetLastError()); @@ -337,8 +341,8 @@ static UINT drive_process_irp_write(DRIVE_DEVICE* drive, IRP* irp) Stream_Read_UINT32(irp->input, Length); Stream_Read_UINT64(irp->input, Offset); Stream_Seek(irp->input, 20); /* Padding */ - file = drive_get_file_by_id(drive, irp->FileId); + if (!file) { irp->IoStatus = STATUS_UNSUCCESSFUL; @@ -377,8 +381,8 @@ static UINT drive_process_irp_query_information(DRIVE_DEVICE* drive, IRP* irp) return ERROR_INVALID_DATA; Stream_Read_UINT32(irp->input, FsInformationClass); - file = drive_get_file_by_id(drive, irp->FileId); + if (!file) { irp->IoStatus = STATUS_UNSUCCESSFUL; @@ -411,8 +415,8 @@ static UINT drive_process_irp_set_information(DRIVE_DEVICE* drive, IRP* irp) Stream_Read_UINT32(irp->input, FsInformationClass); Stream_Read_UINT32(irp->input, Length); Stream_Seek(irp->input, 24); /* Padding */ - file = drive_get_file_by_id(drive, irp->FileId); + if (!file) { irp->IoStatus = STATUS_UNSUCCESSFUL; @@ -523,6 +527,7 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, if (!Stream_EnsureRemainingCapacity(output, 12 + length)) { + free(outStr); WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -595,7 +600,6 @@ static UINT drive_process_irp_silent_ignore(DRIVE_DEVICE* drive, IRP* irp) return ERROR_INVALID_DATA; Stream_Read_UINT32(irp->input, FsInformationClass); - Stream_Write_UINT32(irp->output, 0); /* Length */ return irp->Complete(irp); } @@ -624,8 +628,8 @@ static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp) Stream_Read_UINT32(irp->input, PathLength); Stream_Seek(irp->input, 23); /* Padding */ path = (WCHAR*) Stream_Pointer(irp->input); - file = drive_get_file_by_id(drive, irp->FileId); + if (file == NULL) { irp->IoStatus = STATUS_UNSUCCESSFUL; @@ -689,6 +693,7 @@ static UINT drive_process_irp_device_control(DRIVE_DEVICE* drive, IRP* irp) static UINT drive_process_irp(DRIVE_DEVICE* drive, IRP* irp) { UINT error; + if (!drive || !irp) return ERROR_INVALID_PARAMETER; @@ -752,7 +757,7 @@ static DWORD WINAPI drive_thread_func(LPVOID arg) DRIVE_DEVICE* drive = (DRIVE_DEVICE*) arg; UINT error = CHANNEL_RC_OK; - if(!drive) + if (!drive) { error = ERROR_INVALID_PARAMETER; goto fail; @@ -790,6 +795,7 @@ static DWORD WINAPI drive_thread_func(LPVOID arg) } fail: + if (error && drive && drive->rdpcontext) setChannelError(drive->rdpcontext, error, "drive_thread_func reported an error"); @@ -821,6 +827,7 @@ static UINT drive_irp_request(DEVICE* device, IRP* irp) static UINT drive_free_int(DRIVE_DEVICE* drive) { UINT error = CHANNEL_RC_OK; + if (!drive) return ERROR_INVALID_PARAMETER; @@ -857,32 +864,25 @@ static UINT drive_free(DEVICE* device) return drive_free_int(drive); } +/** + * Helper function used for freeing list dictionary value object + */ +static void drive_file_objfree(void* obj) +{ + drive_file_free((DRIVE_FILE*) obj); +} + /** * Function description * * @return 0 on success, otherwise a Win32 error code */ static UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, - char* name, char* path) + const char* name, const char* path, BOOL automount) { size_t i, length; DRIVE_DEVICE* drive; UINT error; -#ifdef WIN32 - - /* - * We cannot enter paths like c:\ because : is an arg separator - * thus, paths are entered as c+\ and the + is substituted here - */ - if (path[1] == '+') - { - if ((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z')) - { - path[1] = ':'; - } - } - -#endif if (name[0] && path[0]) { @@ -900,6 +900,7 @@ static UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, drive->device.IRPRequest = drive_irp_request; drive->device.Free = drive_free; drive->rdpcontext = pEntryPoints->rdpcontext; + drive->automount = automount; length = strlen(name); drive->device.data = Stream_New(NULL, length + 1); @@ -913,8 +914,8 @@ static UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, for (i = 0; i <= length; i++) Stream_Write_UINT8(drive->device.data, name[i] < 0 ? '_' : name[i]); - if ((pathLength > 1) && (path[pathLength-1] == '/')) - pathLength --; + if ((pathLength > 1) && (path[pathLength - 1] == '/')) + pathLength --; if (ConvertToUnicode(sys_code_page, 0, path, pathLength, &drive->path, 0) <= 0) { @@ -932,7 +933,7 @@ static UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, goto out_error; } - ListDictionary_ValueObject(drive->files)->fnObjectFree = (OBJECT_FREE_FN) drive_file_free; + ListDictionary_ValueObject(drive->files)->fnObjectFree = drive_file_objfree; drive->IrpQueue = MessageQueue_New(NULL); if (!drive->IrpQueue) @@ -1015,7 +1016,7 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) } } - error = drive_register_drive_path(pEntryPoints, drive->Name, drive->Path); + error = drive_register_drive_path(pEntryPoints, drive->Name, drive->Path, drive->automount); #else sys_code_page = GetACP(); @@ -1034,7 +1035,7 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) return CHANNEL_RC_NO_MEMORY; } - error = drive_register_drive_path(pEntryPoints, drive->Name, drive->Path); + error = drive_register_drive_path(pEntryPoints, drive->Name, drive->Path, drive->automount); } else if (strcmp(drive->Path, "*") == 0) { @@ -1065,7 +1066,7 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) return CHANNEL_RC_NO_MEMORY; } - if ((error = drive_register_drive_path(pEntryPoints, bufdup, devdup))) + if ((error = drive_register_drive_path(pEntryPoints, bufdup, devdup, TRUE))) { break; } @@ -1074,7 +1075,7 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) } else { - error = drive_register_drive_path(pEntryPoints, drive->Name, drive->Path); + error = drive_register_drive_path(pEntryPoints, drive->Name, drive->Path, drive->automount); } #endif diff --git a/channels/encomsp/client/encomsp_main.c b/channels/encomsp/client/encomsp_main.c index 35c5756..d595fef 100644 --- a/channels/encomsp/client/encomsp_main.c +++ b/channels/encomsp/client/encomsp_main.c @@ -998,7 +998,6 @@ static VOID VCAPITYPE encomsp_virtual_channel_open_event_ex(LPVOID lpUserParam, break; case CHANNEL_EVENT_WRITE_COMPLETE: - Stream_Free((wStream*) pData, TRUE); break; case CHANNEL_EVENT_USER: @@ -1087,7 +1086,7 @@ static UINT encomsp_virtual_channel_event_connected(encomspPlugin* encomsp, } if (!(encomsp->thread = CreateThread(NULL, 0, - encomsp_virtual_channel_client_thread, (void*) encomsp, + encomsp_virtual_channel_client_thread, (void*) encomsp, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); @@ -1107,6 +1106,9 @@ static UINT encomsp_virtual_channel_event_disconnected(encomspPlugin* encomsp) { UINT rc; + if (encomsp->OpenHandle == 0) + return CHANNEL_RC_OK; + if (MessageQueue_PostQuit(encomsp->queue, 0) && (WaitForSingleObject(encomsp->thread, INFINITE) == WAIT_FAILED)) { @@ -1217,7 +1219,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints, PVOI CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL; - strcpy(encomsp->channelDef.name, "encomsp"); + sprintf_s(encomsp->channelDef.name, ARRAYSIZE(encomsp->channelDef.name), "encomsp"); pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*) pEntryPoints; if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) && diff --git a/channels/printer/client/printer_main.c b/channels/printer/client/printer_main.c index 5074ff1..630c0c0 100644 --- a/channels/printer/client/printer_main.c +++ b/channels/printer/client/printer_main.c @@ -68,6 +68,7 @@ struct _PRINTER_DEVICE HANDLE thread; rdpContext* rdpcontext; + char port[64]; }; /** @@ -322,7 +323,6 @@ static UINT printer_free(DEVICE* device) if (printer_dev->printer) printer_dev->printer->Free(printer_dev->printer); - free(printer_dev->device.name); Stream_Free(printer_dev->device.data, TRUE); free(printer_dev); return CHANNEL_RC_OK; @@ -336,7 +336,6 @@ static UINT printer_free(DEVICE* device) UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, rdpPrinter* printer) { - char* port; UINT32 Flags; int DriverNameLen; WCHAR* DriverName = NULL; @@ -346,26 +345,17 @@ UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, BYTE* CachedPrinterConfigData; PRINTER_DEVICE* printer_dev; UINT error; - port = malloc(10); - - if (!port) - { - WLog_ERR(TAG, "malloc failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - sprintf_s(port, 10, "PRN%d", printer->id); printer_dev = (PRINTER_DEVICE*) calloc(1, sizeof(PRINTER_DEVICE)); if (!printer_dev) { WLog_ERR(TAG, "calloc failed!"); - free(port); return CHANNEL_RC_NO_MEMORY; } + sprintf_s(printer_dev->port, sizeof(printer_dev->port), "PRN%d", printer->id); printer_dev->device.type = RDPDR_DTYP_PRINT; - printer_dev->device.name = port; + printer_dev->device.name = printer_dev->port; printer_dev->device.IRPRequest = printer_irp_request; printer_dev->device.Free = printer_free; printer_dev->rdpcontext = pEntryPoints->rdpcontext; @@ -445,7 +435,8 @@ UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, goto error_out; } - if (!(printer_dev->thread = CreateThread(NULL, 0, printer_thread_func, (void*) printer_dev, 0, NULL))) + if (!(printer_dev->thread = CreateThread(NULL, 0, printer_thread_func, (void*) printer_dev, 0, + NULL))) { WLog_ERR(TAG, "CreateThread failed!"); error = ERROR_INTERNAL_ERROR; @@ -454,12 +445,7 @@ UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, return CHANNEL_RC_OK; error_out: - CloseHandle(printer_dev->stopEvent); - CloseHandle(printer_dev->event); - _aligned_free(printer_dev->pIrpList); - Stream_Free(printer_dev->device.data, TRUE); - free(printer_dev); - free(port); + printer_free(&printer_dev->device); return error; } diff --git a/channels/rail/client/rail_main.c b/channels/rail/client/rail_main.c index e14cb52..ea772dd 100644 --- a/channels/rail/client/rail_main.c +++ b/channels/rail/client/rail_main.c @@ -95,23 +95,6 @@ UINT rail_send_channel_data(railPlugin* rail, void* data, size_t length) return rail_send(rail, s); } -/** - * used by rail_client_execute() to free RAIL_EXEC_ORDER's - * internal malloced memory; - */ -static void rail_client_clean_exec_order(RAIL_EXEC_ORDER* exec) -{ - if (!exec) - return; - - free(exec->exeOrFile.string); - exec->exeOrFile.string = NULL; - free(exec->workingDir.string); - exec->workingDir.string = NULL; - free(exec->arguments.string); - exec->arguments.string = NULL; -} - /** * Callback Interface */ @@ -122,17 +105,22 @@ static void rail_client_clean_exec_order(RAIL_EXEC_ORDER* exec) * @return 0 on success, otherwise a Win32 error code */ static UINT rail_client_execute(RailClientContext* context, - RAIL_EXEC_ORDER* exec) + const RAIL_EXEC_ORDER* exec) { char* exeOrFile; UINT error; railPlugin* rail; + UINT16 flags; + RAIL_UNICODE_STRING ruExeOrFile = { 0 }; + RAIL_UNICODE_STRING ruWorkingDir = { 0 }; + RAIL_UNICODE_STRING ruArguments = { 0 }; if (!context || !exec) return ERROR_INVALID_PARAMETER; rail = (railPlugin*) context->handle; exeOrFile = exec->RemoteApplicationProgram; + flags = exec->flags; if (!exeOrFile) return ERROR_INVALID_PARAMETER; @@ -140,17 +128,22 @@ static UINT rail_client_execute(RailClientContext* context, if (strnlen(exeOrFile, MAX_PATH) >= 2) { if (strncmp(exeOrFile, "||", 2) != 0) - exec->flags |= RAIL_EXEC_FLAG_FILE; + flags |= RAIL_EXEC_FLAG_FILE; } - rail_string_to_unicode_string(exec->RemoteApplicationProgram, - &exec->exeOrFile); /* RemoteApplicationProgram */ - rail_string_to_unicode_string(exec->RemoteApplicationWorkingDir, - &exec->workingDir); /* ShellWorkingDirectory */ - rail_string_to_unicode_string(exec->RemoteApplicationArguments, - &exec->arguments); /* RemoteApplicationCmdLine */ - error = rail_send_client_exec_order(rail, exec); - rail_client_clean_exec_order(exec); + if (!rail_string_to_unicode_string(exec->RemoteApplicationProgram, + &ruExeOrFile) || /* RemoteApplicationProgram */ + !rail_string_to_unicode_string(exec->RemoteApplicationWorkingDir, + &ruWorkingDir) || /* ShellWorkingDirectory */ + !rail_string_to_unicode_string(exec->RemoteApplicationArguments, + &ruArguments)) /* RemoteApplicationCmdLine */ + error = ERROR_INTERNAL_ERROR; + else + error = rail_send_client_exec_order(rail, flags, &ruExeOrFile, &ruWorkingDir, &ruArguments); + + free(ruExeOrFile.string); + free(ruWorkingDir.string); + free(ruArguments.string); return error; } @@ -160,7 +153,7 @@ static UINT rail_client_execute(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_client_activate(RailClientContext* context, - RAIL_ACTIVATE_ORDER* activate) + const RAIL_ACTIVATE_ORDER* activate) { railPlugin* rail; @@ -243,84 +236,87 @@ static UINT rail_send_client_sysparam(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_client_system_param(RailClientContext* context, - RAIL_SYSPARAM_ORDER* sysparam) + const RAIL_SYSPARAM_ORDER* sysInParam) { UINT error = CHANNEL_RC_OK; + RAIL_SYSPARAM_ORDER sysparam; - if (!context || !sysparam) + if (!context || !sysInParam) return ERROR_INVALID_PARAMETER; - if (sysparam->params & SPI_MASK_SET_HIGH_CONTRAST) - { - sysparam->param = SPI_SET_HIGH_CONTRAST; + sysparam = *sysInParam; - if ((error = rail_send_client_sysparam(context, sysparam))) + if (sysparam.params & SPI_MASK_SET_HIGH_CONTRAST) + { + sysparam.param = SPI_SET_HIGH_CONTRAST; + + if ((error = rail_send_client_sysparam(context, &sysparam))) { WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error); return error; } } - if (sysparam->params & SPI_MASK_TASKBAR_POS) + if (sysparam.params & SPI_MASK_TASKBAR_POS) { - sysparam->param = SPI_TASKBAR_POS; + sysparam.param = SPI_TASKBAR_POS; - if ((error = rail_send_client_sysparam(context, sysparam))) + if ((error = rail_send_client_sysparam(context, &sysparam))) { WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error); return error; } } - if (sysparam->params & SPI_MASK_SET_MOUSE_BUTTON_SWAP) + if (sysparam.params & SPI_MASK_SET_MOUSE_BUTTON_SWAP) { - sysparam->param = SPI_SET_MOUSE_BUTTON_SWAP; + sysparam.param = SPI_SET_MOUSE_BUTTON_SWAP; - if ((error = rail_send_client_sysparam(context, sysparam))) + if ((error = rail_send_client_sysparam(context, &sysparam))) { WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error); return error; } } - if (sysparam->params & SPI_MASK_SET_KEYBOARD_PREF) + if (sysparam.params & SPI_MASK_SET_KEYBOARD_PREF) { - sysparam->param = SPI_SET_KEYBOARD_PREF; + sysparam.param = SPI_SET_KEYBOARD_PREF; - if ((error = rail_send_client_sysparam(context, sysparam))) + if ((error = rail_send_client_sysparam(context, &sysparam))) { WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error); return error; } } - if (sysparam->params & SPI_MASK_SET_DRAG_FULL_WINDOWS) + if (sysparam.params & SPI_MASK_SET_DRAG_FULL_WINDOWS) { - sysparam->param = SPI_SET_DRAG_FULL_WINDOWS; + sysparam.param = SPI_SET_DRAG_FULL_WINDOWS; - if ((error = rail_send_client_sysparam(context, sysparam))) + if ((error = rail_send_client_sysparam(context, &sysparam))) { WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error); return error; } } - if (sysparam->params & SPI_MASK_SET_KEYBOARD_CUES) + if (sysparam.params & SPI_MASK_SET_KEYBOARD_CUES) { - sysparam->param = SPI_SET_KEYBOARD_CUES; + sysparam.param = SPI_SET_KEYBOARD_CUES; - if ((error = rail_send_client_sysparam(context, sysparam))) + if ((error = rail_send_client_sysparam(context, &sysparam))) { WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error); return error; } } - if (sysparam->params & SPI_MASK_SET_WORK_AREA) + if (sysparam.params & SPI_MASK_SET_WORK_AREA) { - sysparam->param = SPI_SET_WORK_AREA; + sysparam.param = SPI_SET_WORK_AREA; - if ((error = rail_send_client_sysparam(context, sysparam))) + if ((error = rail_send_client_sysparam(context, &sysparam))) { WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error); return error; @@ -336,7 +332,7 @@ static UINT rail_client_system_param(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_server_system_param(RailClientContext* context, - RAIL_SYSPARAM_ORDER* sysparam) + const RAIL_SYSPARAM_ORDER* sysparam) { if (!context || !sysparam) return ERROR_INVALID_PARAMETER; @@ -350,7 +346,7 @@ static UINT rail_server_system_param(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_client_system_command(RailClientContext* context, - RAIL_SYSCOMMAND_ORDER* syscommand) + const RAIL_SYSCOMMAND_ORDER* syscommand) { railPlugin* rail; @@ -367,7 +363,7 @@ static UINT rail_client_system_command(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_client_handshake(RailClientContext* context, - RAIL_HANDSHAKE_ORDER* handshake) + const RAIL_HANDSHAKE_ORDER* handshake) { railPlugin* rail; @@ -384,7 +380,7 @@ static UINT rail_client_handshake(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_server_handshake(RailClientContext* context, - RAIL_HANDSHAKE_ORDER* handshake) + const RAIL_HANDSHAKE_ORDER* handshake) { if (!context || !handshake) return ERROR_INVALID_PARAMETER; @@ -398,7 +394,7 @@ static UINT rail_server_handshake(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_client_handshake_ex(RailClientContext* context, - RAIL_HANDSHAKE_EX_ORDER* handshakeEx) + const RAIL_HANDSHAKE_EX_ORDER* handshakeEx) { railPlugin* rail; @@ -415,7 +411,7 @@ static UINT rail_client_handshake_ex(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_server_handshake_ex(RailClientContext* context, - RAIL_HANDSHAKE_EX_ORDER* handshakeEx) + const RAIL_HANDSHAKE_EX_ORDER* handshakeEx) { if (!context || !handshakeEx) return ERROR_INVALID_PARAMETER; @@ -429,7 +425,7 @@ static UINT rail_server_handshake_ex(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_client_notify_event(RailClientContext* context, - RAIL_NOTIFY_EVENT_ORDER* notifyEvent) + const RAIL_NOTIFY_EVENT_ORDER* notifyEvent) { railPlugin* rail; @@ -446,7 +442,7 @@ static UINT rail_client_notify_event(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_client_window_move(RailClientContext* context, - RAIL_WINDOW_MOVE_ORDER* windowMove) + const RAIL_WINDOW_MOVE_ORDER* windowMove) { railPlugin* rail; @@ -463,7 +459,7 @@ static UINT rail_client_window_move(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_server_local_move_size(RailClientContext* context, - RAIL_LOCALMOVESIZE_ORDER* localMoveSize) + const RAIL_LOCALMOVESIZE_ORDER* localMoveSize) { if (!context || !localMoveSize) return ERROR_INVALID_PARAMETER; @@ -477,7 +473,7 @@ static UINT rail_server_local_move_size(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_server_min_max_info(RailClientContext* context, - RAIL_MINMAXINFO_ORDER* minMaxInfo) + const RAIL_MINMAXINFO_ORDER* minMaxInfo) { if (!context || !minMaxInfo) return ERROR_INVALID_PARAMETER; @@ -491,7 +487,7 @@ static UINT rail_server_min_max_info(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_client_information(RailClientContext* context, - RAIL_CLIENT_STATUS_ORDER* clientStatus) + const RAIL_CLIENT_STATUS_ORDER* clientStatus) { railPlugin* rail; @@ -508,7 +504,7 @@ static UINT rail_client_information(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_client_system_menu(RailClientContext* context, - RAIL_SYSMENU_ORDER* sysmenu) + const RAIL_SYSMENU_ORDER* sysmenu) { railPlugin* rail; @@ -525,7 +521,7 @@ static UINT rail_client_system_menu(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_client_language_bar_info(RailClientContext* context, - RAIL_LANGBAR_INFO_ORDER* langBarInfo) + const RAIL_LANGBAR_INFO_ORDER* langBarInfo) { railPlugin* rail; @@ -542,7 +538,7 @@ static UINT rail_client_language_bar_info(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_server_language_bar_info(RailClientContext* context, - RAIL_LANGBAR_INFO_ORDER* langBarInfo) + const RAIL_LANGBAR_INFO_ORDER* langBarInfo) { if (!context || !langBarInfo) return ERROR_INVALID_PARAMETER; @@ -556,7 +552,7 @@ static UINT rail_server_language_bar_info(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_server_execute_result(RailClientContext* context, - RAIL_EXEC_RESULT_ORDER* execResult) + const RAIL_EXEC_RESULT_ORDER* execResult) { if (!context || !execResult) return ERROR_INVALID_PARAMETER; @@ -570,7 +566,7 @@ static UINT rail_server_execute_result(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_client_get_appid_request(RailClientContext* context, - RAIL_GET_APPID_REQ_ORDER* getAppIdReq) + const RAIL_GET_APPID_REQ_ORDER* getAppIdReq) { railPlugin* rail; @@ -587,7 +583,7 @@ static UINT rail_client_get_appid_request(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_server_get_appid_response(RailClientContext* context, - RAIL_GET_APPID_RESP_ORDER* getAppIdResp) + const RAIL_GET_APPID_RESP_ORDER* getAppIdResp) { if (!context || !getAppIdResp) return ERROR_INVALID_PARAMETER; @@ -680,7 +676,6 @@ static VOID VCAPITYPE rail_virtual_channel_open_event_ex(LPVOID lpUserParam, DWO break; case CHANNEL_EVENT_WRITE_COMPLETE: - Stream_Free((wStream*) pData, TRUE); break; case CHANNEL_EVENT_USER: @@ -770,7 +765,7 @@ static UINT rail_virtual_channel_event_connected(railPlugin* rail, LPVOID pData, } if (!(rail->thread = CreateThread(NULL, 0, - rail_virtual_channel_client_thread, (void*) rail, 0, + rail_virtual_channel_client_thread, (void*) rail, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); @@ -791,6 +786,9 @@ static UINT rail_virtual_channel_event_disconnected(railPlugin* rail) { UINT rc; + if (rail->OpenHandle == 0) + return CHANNEL_RC_OK; + if (MessageQueue_PostQuit(rail->queue, 0) && (WaitForSingleObject(rail->thread, INFINITE) == WAIT_FAILED)) { @@ -895,7 +893,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL; - strcpy(rail->channelDef.name, "rail"); + sprintf_s(rail->channelDef.name, ARRAYSIZE(rail->channelDef.name), "rail"); pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*) pEntryPoints; if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) && diff --git a/channels/rail/client/rail_orders.c b/channels/rail/client/rail_orders.c index 7e489e3..7e6cf42 100644 --- a/channels/rail/client/rail_orders.c +++ b/channels/rail/client/rail_orders.c @@ -37,7 +37,7 @@ * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_write_unicode_string(wStream* s, RAIL_UNICODE_STRING* unicode_string) +static UINT rail_write_unicode_string(wStream* s, const RAIL_UNICODE_STRING* unicode_string) { if (!s || !unicode_string) return ERROR_INVALID_PARAMETER; @@ -58,20 +58,24 @@ static UINT rail_write_unicode_string(wStream* s, RAIL_UNICODE_STRING* unicode_s * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_write_unicode_string_value(wStream* s, RAIL_UNICODE_STRING* unicode_string) +static UINT rail_write_unicode_string_value(wStream* s, const RAIL_UNICODE_STRING* unicode_string) { + size_t length; + if (!s || !unicode_string) return ERROR_INVALID_PARAMETER; - if (unicode_string->length > 0) + length = unicode_string->length; + + if (length > 0) { - if (!Stream_EnsureRemainingCapacity(s, unicode_string->length)) + if (!Stream_EnsureRemainingCapacity(s, length)) { WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); return CHANNEL_RC_NO_MEMORY; } - Stream_Write(s, unicode_string->string, unicode_string->length); /* string */ + Stream_Write(s, unicode_string->string, length); /* string */ } return CHANNEL_RC_OK; @@ -103,14 +107,16 @@ UINT rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType) * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_write_high_contrast(wStream* s, RAIL_HIGH_CONTRAST* highContrast) +static UINT rail_write_high_contrast(wStream* s, const RAIL_HIGH_CONTRAST* highContrast) { + UINT32 colorSchemeLength; + if (!s || !highContrast) return ERROR_INVALID_PARAMETER; - highContrast->colorSchemeLength = highContrast->colorScheme.length + 2; + colorSchemeLength = highContrast->colorScheme.length + 2; Stream_Write_UINT32(s, highContrast->flags); /* flags (4 bytes) */ - Stream_Write_UINT32(s, highContrast->colorSchemeLength); /* colorSchemeLength (4 bytes) */ + Stream_Write_UINT32(s, colorSchemeLength); /* colorSchemeLength (4 bytes) */ return rail_write_unicode_string(s, &highContrast->colorScheme); /* colorScheme */ } @@ -275,7 +281,7 @@ static UINT rail_read_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* la return CHANNEL_RC_OK; } -static UINT rail_write_client_status_order(wStream* s, RAIL_CLIENT_STATUS_ORDER* clientStatus) +static UINT rail_write_client_status_order(wStream* s, const RAIL_CLIENT_STATUS_ORDER* clientStatus) { if (!s || !clientStatus) return ERROR_INVALID_PARAMETER; @@ -289,31 +295,44 @@ static UINT rail_write_client_status_order(wStream* s, RAIL_CLIENT_STATUS_ORDER* * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_write_client_exec_order(wStream* s, RAIL_EXEC_ORDER* exec) +static UINT rail_write_client_exec_order(wStream* s, UINT16 flags, + const RAIL_UNICODE_STRING* exeOrFile, const RAIL_UNICODE_STRING* workingDir, + const RAIL_UNICODE_STRING* arguments) { UINT error; - if (!s || !exec) + if (!s || !exeOrFile || !workingDir || !arguments) return ERROR_INVALID_PARAMETER; - Stream_Write_UINT16(s, exec->flags); /* flags (2 bytes) */ - Stream_Write_UINT16(s, exec->exeOrFile.length); /* exeOrFileLength (2 bytes) */ - Stream_Write_UINT16(s, exec->workingDir.length); /* workingDirLength (2 bytes) */ - Stream_Write_UINT16(s, exec->arguments.length); /* argumentsLength (2 bytes) */ + /* [MS-RDPERP] 2.2.2.3.1 Client Execute PDU (TS_RAIL_ORDER_EXEC) + * Check argument limits */ + if ((exeOrFile->length > 520) || (workingDir->length > 520) || + (arguments->length > 16000)) + { + WLog_ERR(TAG, + "TS_RAIL_ORDER_EXEC argument limits exceeded: ExeOrFile=%"PRIu16" [max=520], WorkingDir=%"PRIu16" [max=520], Arguments=%"PRIu16" [max=16000]", + exeOrFile->length, workingDir->length, arguments->length); + return ERROR_BAD_ARGUMENTS; + } - if ((error = rail_write_unicode_string_value(s, &exec->exeOrFile))) + Stream_Write_UINT16(s, flags); /* flags (2 bytes) */ + Stream_Write_UINT16(s, exeOrFile->length); /* exeOrFileLength (2 bytes) */ + Stream_Write_UINT16(s, workingDir->length); /* workingDirLength (2 bytes) */ + Stream_Write_UINT16(s, arguments->length); /* argumentsLength (2 bytes) */ + + if ((error = rail_write_unicode_string_value(s, exeOrFile))) { WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %"PRIu32"", error); return error; } - if ((error = rail_write_unicode_string_value(s, &exec->workingDir))) + if ((error = rail_write_unicode_string_value(s, workingDir))) { WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %"PRIu32"", error); return error; } - if ((error = rail_write_unicode_string_value(s, &exec->arguments))) + if ((error = rail_write_unicode_string_value(s, arguments))) { WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %"PRIu32"", error); return error; @@ -327,7 +346,7 @@ static UINT rail_write_client_exec_order(wStream* s, RAIL_EXEC_ORDER* exec) * * @return 0 on success, otherwise a Win32 error code */ -UINT rail_write_client_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam) +UINT rail_write_client_sysparam_order(wStream* s, const RAIL_SYSPARAM_ORDER* sysparam) { BYTE body; UINT error = CHANNEL_RC_OK; @@ -340,22 +359,22 @@ UINT rail_write_client_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam) switch (sysparam->param) { case SPI_SET_DRAG_FULL_WINDOWS: - body = sysparam->dragFullWindows; + body = sysparam->dragFullWindows ? 1 : 0; Stream_Write_UINT8(s, body); break; case SPI_SET_KEYBOARD_CUES: - body = sysparam->keyboardCues; + body = sysparam->keyboardCues ? 1 : 0; Stream_Write_UINT8(s, body); break; case SPI_SET_KEYBOARD_PREF: - body = sysparam->keyboardPref; + body = sysparam->keyboardPref ? 1 : 0; Stream_Write_UINT8(s, body); break; case SPI_SET_MOUSE_BUTTON_SWAP: - body = sysparam->mouseButtonSwap; + body = sysparam->mouseButtonSwap ? 1 : 0; Stream_Write_UINT8(s, body); break; @@ -388,7 +407,7 @@ UINT rail_write_client_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam) return error; } -static UINT rail_write_client_activate_order(wStream* s, RAIL_ACTIVATE_ORDER* activate) +static UINT rail_write_client_activate_order(wStream* s, const RAIL_ACTIVATE_ORDER* activate) { BYTE enabled; @@ -396,12 +415,12 @@ static UINT rail_write_client_activate_order(wStream* s, RAIL_ACTIVATE_ORDER* ac return ERROR_INVALID_PARAMETER; Stream_Write_UINT32(s, activate->windowId); /* windowId (4 bytes) */ - enabled = activate->enabled; + enabled = activate->enabled ? 1 : 0; Stream_Write_UINT8(s, enabled); /* enabled (1 byte) */ return ERROR_SUCCESS; } -static UINT rail_write_client_sysmenu_order(wStream* s, RAIL_SYSMENU_ORDER* sysmenu) +static UINT rail_write_client_sysmenu_order(wStream* s, const RAIL_SYSMENU_ORDER* sysmenu) { if (!s || !sysmenu) return ERROR_INVALID_PARAMETER; @@ -412,7 +431,7 @@ static UINT rail_write_client_sysmenu_order(wStream* s, RAIL_SYSMENU_ORDER* sysm return ERROR_SUCCESS; } -static UINT rail_write_client_syscommand_order(wStream* s, RAIL_SYSCOMMAND_ORDER* syscommand) +static UINT rail_write_client_syscommand_order(wStream* s, const RAIL_SYSCOMMAND_ORDER* syscommand) { if (!s || !syscommand) return ERROR_INVALID_PARAMETER; @@ -422,7 +441,8 @@ static UINT rail_write_client_syscommand_order(wStream* s, RAIL_SYSCOMMAND_ORDER return ERROR_SUCCESS; } -static UINT rail_write_client_notify_event_order(wStream* s, RAIL_NOTIFY_EVENT_ORDER* notifyEvent) +static UINT rail_write_client_notify_event_order(wStream* s, + const RAIL_NOTIFY_EVENT_ORDER* notifyEvent) { if (!s || !notifyEvent) return ERROR_INVALID_PARAMETER; @@ -433,7 +453,8 @@ static UINT rail_write_client_notify_event_order(wStream* s, RAIL_NOTIFY_EVENT_O return ERROR_SUCCESS; } -static UINT rail_write_client_window_move_order(wStream* s, RAIL_WINDOW_MOVE_ORDER* windowMove) +static UINT rail_write_client_window_move_order(wStream* s, + const RAIL_WINDOW_MOVE_ORDER* windowMove) { if (!s || !windowMove) return ERROR_INVALID_PARAMETER; @@ -446,7 +467,8 @@ static UINT rail_write_client_window_move_order(wStream* s, RAIL_WINDOW_MOVE_ORD return ERROR_SUCCESS; } -static UINT rail_write_client_get_appid_req_order(wStream* s, RAIL_GET_APPID_REQ_ORDER* getAppidReq) +static UINT rail_write_client_get_appid_req_order(wStream* s, + const RAIL_GET_APPID_REQ_ORDER* getAppidReq) { if (!s || !getAppidReq) return ERROR_INVALID_PARAMETER; @@ -455,7 +477,7 @@ static UINT rail_write_client_get_appid_req_order(wStream* s, RAIL_GET_APPID_REQ return ERROR_SUCCESS; } -static UINT rail_write_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* langbarInfo) +static UINT rail_write_langbar_info_order(wStream* s, const RAIL_LANGBAR_INFO_ORDER* langbarInfo) { if (!s || !langbarInfo) return ERROR_INVALID_PARAMETER; @@ -753,7 +775,7 @@ UINT rail_order_recv(railPlugin* rail, wStream* s) case RDP_RAIL_ORDER_EXEC_RESULT: { - RAIL_EXEC_RESULT_ORDER execResult; + RAIL_EXEC_RESULT_ORDER execResult = { 0 }; error = rail_recv_exec_result_order(rail, &execResult, s); free(execResult.exeOrFile.string); return error; @@ -802,7 +824,7 @@ UINT rail_order_recv(railPlugin* rail, wStream* s) * * @return 0 on success, otherwise a Win32 error code */ -UINT rail_send_handshake_order(railPlugin* rail, RAIL_HANDSHAKE_ORDER* handshake) +UINT rail_send_handshake_order(railPlugin* rail, const RAIL_HANDSHAKE_ORDER* handshake) { wStream* s; UINT error; @@ -829,7 +851,7 @@ UINT rail_send_handshake_order(railPlugin* rail, RAIL_HANDSHAKE_ORDER* handshake * * @return 0 on success, otherwise a Win32 error code */ -UINT rail_send_handshake_ex_order(railPlugin* rail, RAIL_HANDSHAKE_EX_ORDER* handshakeEx) +UINT rail_send_handshake_ex_order(railPlugin* rail, const RAIL_HANDSHAKE_EX_ORDER* handshakeEx) { wStream* s; UINT error; @@ -856,7 +878,7 @@ UINT rail_send_handshake_ex_order(railPlugin* rail, RAIL_HANDSHAKE_EX_ORDER* han * * @return 0 on success, otherwise a Win32 error code */ -UINT rail_send_client_status_order(railPlugin* rail, RAIL_CLIENT_STATUS_ORDER* clientStatus) +UINT rail_send_client_status_order(railPlugin* rail, const RAIL_CLIENT_STATUS_ORDER* clientStatus) { wStream* s; UINT error; @@ -886,19 +908,21 @@ UINT rail_send_client_status_order(railPlugin* rail, RAIL_CLIENT_STATUS_ORDER* c * * @return 0 on success, otherwise a Win32 error code */ -UINT rail_send_client_exec_order(railPlugin* rail, RAIL_EXEC_ORDER* exec) +UINT rail_send_client_exec_order(railPlugin* rail, UINT16 flags, + const RAIL_UNICODE_STRING* exeOrFile, const RAIL_UNICODE_STRING* workingDir, + const RAIL_UNICODE_STRING* arguments) { wStream* s; UINT error; size_t length; - if (!rail || !exec) + if (!rail || !exeOrFile || !workingDir || !arguments) return ERROR_INVALID_PARAMETER; length = RAIL_EXEC_ORDER_LENGTH + - exec->exeOrFile.length + - exec->workingDir.length + - exec->arguments.length; + exeOrFile->length + + workingDir->length + + arguments->length; s = rail_pdu_init(length); if (!s) @@ -907,18 +931,19 @@ UINT rail_send_client_exec_order(railPlugin* rail, RAIL_EXEC_ORDER* exec) return CHANNEL_RC_NO_MEMORY; } - if ((error = rail_write_client_exec_order(s, exec))) + if ((error = rail_write_client_exec_order(s, flags, exeOrFile, workingDir, arguments))) { WLog_ERR(TAG, "rail_write_client_exec_order failed with error %"PRIu32"!", error); - return error; + goto out; } if ((error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_EXEC))) { WLog_ERR(TAG, "rail_send_pdu failed with error %"PRIu32"!", error); - return error; + goto out; } +out: Stream_Free(s, TRUE); return error; } @@ -928,7 +953,7 @@ UINT rail_send_client_exec_order(railPlugin* rail, RAIL_EXEC_ORDER* exec) * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_send_client_sysparam_order(railPlugin* rail, RAIL_SYSPARAM_ORDER* sysparam) +static UINT rail_send_client_sysparam_order(railPlugin* rail, const RAIL_SYSPARAM_ORDER* sysparam) { wStream* s; size_t length = RAIL_SYSPARAM_ORDER_LENGTH; @@ -972,15 +997,16 @@ static UINT rail_send_client_sysparam_order(railPlugin* rail, RAIL_SYSPARAM_ORDE if ((error = rail_write_client_sysparam_order(s, sysparam))) { WLog_ERR(TAG, "rail_write_client_sysparam_order failed with error %"PRIu32"!", error); - return error; + goto out; } if ((error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_SYSPARAM))) { WLog_ERR(TAG, "rail_send_pdu failed with error %"PRIu32"!", error); - return error; + goto out; } +out: Stream_Free(s, TRUE); return error; } @@ -1082,7 +1108,7 @@ static UINT rail_send_client_sysparams_order(railPlugin* rail, RAIL_SYSPARAM_ORD * * @return 0 on success, otherwise a Win32 error code */ -UINT rail_send_client_activate_order(railPlugin* rail, RAIL_ACTIVATE_ORDER* activate) +UINT rail_send_client_activate_order(railPlugin* rail, const RAIL_ACTIVATE_ORDER* activate) { wStream* s; UINT error; @@ -1112,7 +1138,7 @@ UINT rail_send_client_activate_order(railPlugin* rail, RAIL_ACTIVATE_ORDER* acti * * @return 0 on success, otherwise a Win32 error code */ -UINT rail_send_client_sysmenu_order(railPlugin* rail, RAIL_SYSMENU_ORDER* sysmenu) +UINT rail_send_client_sysmenu_order(railPlugin* rail, const RAIL_SYSMENU_ORDER* sysmenu) { wStream* s; UINT error; @@ -1142,7 +1168,7 @@ UINT rail_send_client_sysmenu_order(railPlugin* rail, RAIL_SYSMENU_ORDER* sysmen * * @return 0 on success, otherwise a Win32 error code */ -UINT rail_send_client_syscommand_order(railPlugin* rail, RAIL_SYSCOMMAND_ORDER* syscommand) +UINT rail_send_client_syscommand_order(railPlugin* rail, const RAIL_SYSCOMMAND_ORDER* syscommand) { wStream* s; UINT error; @@ -1172,7 +1198,8 @@ UINT rail_send_client_syscommand_order(railPlugin* rail, RAIL_SYSCOMMAND_ORDER* * * @return 0 on success, otherwise a Win32 error code */ -UINT rail_send_client_notify_event_order(railPlugin* rail, RAIL_NOTIFY_EVENT_ORDER* notifyEvent) +UINT rail_send_client_notify_event_order(railPlugin* rail, + const RAIL_NOTIFY_EVENT_ORDER* notifyEvent) { wStream* s; UINT error; @@ -1202,7 +1229,7 @@ UINT rail_send_client_notify_event_order(railPlugin* rail, RAIL_NOTIFY_EVENT_ORD * * @return 0 on success, otherwise a Win32 error code */ -UINT rail_send_client_window_move_order(railPlugin* rail, RAIL_WINDOW_MOVE_ORDER* windowMove) +UINT rail_send_client_window_move_order(railPlugin* rail, const RAIL_WINDOW_MOVE_ORDER* windowMove) { wStream* s; UINT error; @@ -1232,7 +1259,8 @@ UINT rail_send_client_window_move_order(railPlugin* rail, RAIL_WINDOW_MOVE_ORDER * * @return 0 on success, otherwise a Win32 error code */ -UINT rail_send_client_get_appid_req_order(railPlugin* rail, RAIL_GET_APPID_REQ_ORDER* getAppIdReq) +UINT rail_send_client_get_appid_req_order(railPlugin* rail, + const RAIL_GET_APPID_REQ_ORDER* getAppIdReq) { wStream* s; UINT error; @@ -1262,7 +1290,8 @@ UINT rail_send_client_get_appid_req_order(railPlugin* rail, RAIL_GET_APPID_REQ_O * * @return 0 on success, otherwise a Win32 error code */ -UINT rail_send_client_langbar_info_order(railPlugin* rail, RAIL_LANGBAR_INFO_ORDER* langBarInfo) +UINT rail_send_client_langbar_info_order(railPlugin* rail, + const RAIL_LANGBAR_INFO_ORDER* langBarInfo) { wStream* s; UINT error; diff --git a/channels/rail/client/rail_orders.h b/channels/rail/client/rail_orders.h index 028286a..0b4fd93 100644 --- a/channels/rail/client/rail_orders.h +++ b/channels/rail/client/rail_orders.h @@ -29,22 +29,27 @@ #define TAG CHANNELS_TAG("rail.client") -UINT rail_write_client_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam); +UINT rail_write_client_sysparam_order(wStream* s, const RAIL_SYSPARAM_ORDER* sysparam); UINT rail_order_recv(railPlugin* rail, wStream* s); UINT rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType); -UINT rail_send_handshake_order(railPlugin* rail, RAIL_HANDSHAKE_ORDER* handshake); -UINT rail_send_handshake_ex_order(railPlugin* rail, RAIL_HANDSHAKE_EX_ORDER* handshakeEx); -UINT rail_send_client_status_order(railPlugin* rail, RAIL_CLIENT_STATUS_ORDER* clientStatus); -UINT rail_send_client_exec_order(railPlugin* rail, RAIL_EXEC_ORDER* exec); -UINT rail_send_client_activate_order(railPlugin* rail, RAIL_ACTIVATE_ORDER* activate); -UINT rail_send_client_sysmenu_order(railPlugin* rail, RAIL_SYSMENU_ORDER* sysmenu); -UINT rail_send_client_syscommand_order(railPlugin* rail, RAIL_SYSCOMMAND_ORDER* syscommand); +UINT rail_send_handshake_order(railPlugin* rail, const RAIL_HANDSHAKE_ORDER* handshake); +UINT rail_send_handshake_ex_order(railPlugin* rail, const RAIL_HANDSHAKE_EX_ORDER* handshakeEx); +UINT rail_send_client_status_order(railPlugin* rail, const RAIL_CLIENT_STATUS_ORDER* clientStatus); +UINT rail_send_client_exec_order(railPlugin* rail, UINT16 flags, + const RAIL_UNICODE_STRING* exeOrFile, const RAIL_UNICODE_STRING* workingDir, + const RAIL_UNICODE_STRING* arguments); +UINT rail_send_client_activate_order(railPlugin* rail, const RAIL_ACTIVATE_ORDER* activate); +UINT rail_send_client_sysmenu_order(railPlugin* rail, const RAIL_SYSMENU_ORDER* sysmenu); +UINT rail_send_client_syscommand_order(railPlugin* rail, const RAIL_SYSCOMMAND_ORDER* syscommand); -UINT rail_send_client_notify_event_order(railPlugin* rail, RAIL_NOTIFY_EVENT_ORDER* notifyEvent); -UINT rail_send_client_window_move_order(railPlugin* rail, RAIL_WINDOW_MOVE_ORDER* windowMove); -UINT rail_send_client_get_appid_req_order(railPlugin* rail, RAIL_GET_APPID_REQ_ORDER* getAppIdReq); -UINT rail_send_client_langbar_info_order(railPlugin* rail, RAIL_LANGBAR_INFO_ORDER* langBarInfo); +UINT rail_send_client_notify_event_order(railPlugin* rail, + const RAIL_NOTIFY_EVENT_ORDER* notifyEvent); +UINT rail_send_client_window_move_order(railPlugin* rail, const RAIL_WINDOW_MOVE_ORDER* windowMove); +UINT rail_send_client_get_appid_req_order(railPlugin* rail, + const RAIL_GET_APPID_REQ_ORDER* getAppIdReq); +UINT rail_send_client_langbar_info_order(railPlugin* rail, + const RAIL_LANGBAR_INFO_ORDER* langBarInfo); #endif /* FREERDP_CHANNEL_RAIL_CLIENT_ORDERS_H */ diff --git a/channels/rail/rail_common.c b/channels/rail/rail_common.c index ea344c3..ac0103f 100644 --- a/channels/rail/rail_common.c +++ b/channels/rail/rail_common.c @@ -51,7 +51,7 @@ const char* const RAIL_ORDER_TYPE_STRINGS[] = "" }; -void rail_string_to_unicode_string(char* string, RAIL_UNICODE_STRING* unicode_string) +BOOL rail_string_to_unicode_string(const char* string, RAIL_UNICODE_STRING* unicode_string) { WCHAR* buffer = NULL; int length = 0; @@ -60,11 +60,19 @@ void rail_string_to_unicode_string(char* string, RAIL_UNICODE_STRING* unicode_st unicode_string->length = 0; if (!string || strlen(string) < 1) - return; + return TRUE; + + length = ConvertToUnicode(CP_UTF8, 0, string, -1, &buffer, 0); + + if ((length < 0) || ((size_t)length * sizeof(WCHAR) > UINT16_MAX)) + { + free(buffer); + return FALSE; + } - length = ConvertToUnicode(CP_UTF8, 0, string, -1, &buffer, 0) * 2; unicode_string->string = (BYTE*) buffer; - unicode_string->length = (UINT16) length; + unicode_string->length = (UINT16) length * sizeof(WCHAR); + return TRUE; } /** @@ -117,7 +125,7 @@ UINT rail_read_handshake_order(wStream* s, RAIL_HANDSHAKE_ORDER* handshake) return CHANNEL_RC_OK; } -void rail_write_handshake_order(wStream* s, RAIL_HANDSHAKE_ORDER* handshake) +void rail_write_handshake_order(wStream* s, const RAIL_HANDSHAKE_ORDER* handshake) { Stream_Write_UINT32(s, handshake->buildNumber); /* buildNumber (4 bytes) */ } @@ -137,7 +145,7 @@ UINT rail_read_handshake_ex_order(wStream* s, RAIL_HANDSHAKE_EX_ORDER* handshake return CHANNEL_RC_OK; } -void rail_write_handshake_ex_order(wStream* s, RAIL_HANDSHAKE_EX_ORDER* handshakeEx) +void rail_write_handshake_ex_order(wStream* s, const RAIL_HANDSHAKE_EX_ORDER* handshakeEx) { Stream_Write_UINT32(s, handshakeEx->buildNumber); /* buildNumber (4 bytes) */ Stream_Write_UINT32(s, handshakeEx->railHandshakeFlags); /* railHandshakeFlags (4 bytes) */ diff --git a/channels/rail/rail_common.h b/channels/rail/rail_common.h index 15d65d4..fe1bc02 100644 --- a/channels/rail/rail_common.h +++ b/channels/rail/rail_common.h @@ -44,11 +44,11 @@ extern const char* const RAIL_ORDER_TYPE_STRINGS[]; #define RAIL_GET_APPID_REQ_ORDER_LENGTH 4 /* fixed */ #define RAIL_LANGBAR_INFO_ORDER_LENGTH 4 /* fixed */ -void rail_string_to_unicode_string(char* string, RAIL_UNICODE_STRING* unicode_string); +BOOL rail_string_to_unicode_string(const char* string, RAIL_UNICODE_STRING* unicode_string); UINT rail_read_handshake_order(wStream* s, RAIL_HANDSHAKE_ORDER* handshake); -void rail_write_handshake_order(wStream* s, RAIL_HANDSHAKE_ORDER* handshake); +void rail_write_handshake_order(wStream* s, const RAIL_HANDSHAKE_ORDER* handshake); UINT rail_read_handshake_ex_order(wStream* s, RAIL_HANDSHAKE_EX_ORDER* handshakeEx); -void rail_write_handshake_ex_order(wStream* s, RAIL_HANDSHAKE_EX_ORDER* handshakeEx); +void rail_write_handshake_ex_order(wStream* s, const RAIL_HANDSHAKE_EX_ORDER* handshakeEx); wStream* rail_pdu_init(size_t length); UINT rail_read_pdu_header(wStream* s, UINT16* orderType, UINT16* orderLength); diff --git a/channels/rdpdr/client/devman.c b/channels/rdpdr/client/devman.c index 3f5dd15..93db1b7 100644 --- a/channels/rdpdr/client/devman.c +++ b/channels/rdpdr/client/devman.c @@ -41,8 +41,10 @@ #include "devman.h" -void devman_device_free(DEVICE* device) +static void devman_device_free(void* obj) { + DEVICE* device = (DEVICE*) obj; + if (!device) return; @@ -75,8 +77,7 @@ DEVMAN* devman_new(rdpdrPlugin* rdpdr) return NULL; } - ListDictionary_ValueObject(devman->devices)->fnObjectFree = - (OBJECT_FREE_FN) devman_device_free; + ListDictionary_ValueObject(devman->devices)->fnObjectFree = devman_device_free; return devman; } diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index 3f16ca9..602268f 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -68,11 +68,12 @@ #include "rdpdr_main.h" typedef struct _DEVICE_DRIVE_EXT DEVICE_DRIVE_EXT; - +/* IMPORTANT: Keep in sync with DRIVE_DEVICE */ struct _DEVICE_DRIVE_EXT { DEVICE device; WCHAR* path; + BOOL automount; }; /** @@ -134,7 +135,7 @@ BOOL check_path(char* path) { UINT type = GetDriveTypeA(path); - if (!(type == DRIVE_REMOVABLE || type == DRIVE_CDROM || type == DRIVE_REMOTE)) + if (!(type == DRIVE_FIXED ||type == DRIVE_REMOVABLE || type == DRIVE_CDROM || type == DRIVE_REMOTE)) return FALSE; return GetVolumeInformationA(path, NULL, 0, NULL, NULL, NULL, NULL, 0); @@ -162,6 +163,7 @@ void first_hotplug(rdpdrPlugin* rdpdr) drive->Path = _strdup(drive_path); drive_path[1] = '\0'; drive->Name = _strdup(drive_path); + drive->automount = TRUE; devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE*)drive, rdpdr->rdpcontext); } @@ -206,6 +208,7 @@ LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) drive->Type = RDPDR_DTYP_FILESYSTEM; drive->Path = _strdup(drive_path); drive_path[1] = '\0'; + drive->automount = TRUE; drive->Name = _strdup(drive_path); devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE*)drive, rdpdr->rdpcontext); @@ -226,7 +229,7 @@ LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) DWORD unitmask = lpdbv->dbcv_unitmask; int i, j, count; char drive_name_upper, drive_name_lower; - ULONG_PTR* keys; + ULONG_PTR* keys = NULL; DEVICE_DRIVE_EXT* device_ext; UINT32 ids[1]; @@ -246,19 +249,24 @@ LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) if (device_ext->path[0] == drive_name_upper || device_ext->path[0] == drive_name_lower) { - devman_unregister_device(rdpdr->devman, (void*)keys[j]); - ids[0] = keys[j]; - - if ((error = rdpdr_send_device_list_remove_request(rdpdr, 1, ids))) + if (device_ext->automount) { - // dont end on error, just report ? - WLog_ERR(TAG, "rdpdr_send_device_list_remove_request failed with error %"PRIu32"!", - error); - } + devman_unregister_device(rdpdr->devman, (void*)keys[j]); + ids[0] = keys[j]; - break; + if ((error = rdpdr_send_device_list_remove_request(rdpdr, 1, ids))) + { + // dont end on error, just report ? + WLog_ERR(TAG, "rdpdr_send_device_list_remove_request failed with error %"PRIu32"!", + error); + } + + break; + } } } + + free(keys); } unitmask = unitmask >> 1; @@ -378,7 +386,7 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) hotplug_dev dev_array[MAX_USB_DEVICES]; int count; DEVICE_DRIVE_EXT* device_ext; - ULONG_PTR* keys; + ULONG_PTR* keys = NULL; int i, j; int size = 0; UINT error; @@ -395,7 +403,7 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) { if (pDirent->d_name[0] != '.') { - sprintf(fullpath, "%s/%s", szdir, pDirent->d_name); + sprintf_s(fullpath, ARRAYSIZE(fullpath), "%s/%s", szdir, pDirent->d_name); lstat(fullpath, &buf); if (S_ISDIR(buf.st_mode)) @@ -425,13 +433,13 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) device_ext = (DEVICE_DRIVE_EXT*)ListDictionary_GetItemValue( rdpdr->devman->devices, (void*)keys[j]); - if (!device_ext) + if (!device_ext || !device_ext->automount) continue; if (device_ext->path == NULL) continue; - if (ConvertFromUnicode(CP_UTF8, 0, device_ext->path, 0, &path, 0, NULL, FALSE) <= 0) + if (ConvertFromUnicode(CP_UTF8, 0, device_ext->path, -1, &path, 0, NULL, FALSE) <= 0) continue; /* not plugable device */ @@ -486,6 +494,7 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) drive->Type = RDPDR_DTYP_FILESYSTEM; drive->Path = dev_array[i].path; + drive->automount = TRUE; dev_array[i].path = NULL; name = strrchr(drive->Path, '/') + 1; drive->Name = _strdup(name); @@ -513,6 +522,7 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) } cleanup: + free(keys); for (i = 0; i < size; i++) free(dev_array[i].path); @@ -692,7 +702,10 @@ static char* next_line(FILE* fd, size_t* len) c = fgetc(fd); if (ferror(fd)) + { + free(newbuf); return NULL; + } if (c == EOF) { @@ -781,7 +794,7 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) int i, j; int size = 0; int count; - ULONG_PTR* keys; + ULONG_PTR* keys = NULL; UINT32 ids[1]; UINT error = 0; memset(dev_array, 0, sizeof(dev_array)); @@ -823,7 +836,7 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) DEVICE_DRIVE_EXT* device_ext = (DEVICE_DRIVE_EXT*)ListDictionary_GetItemValue( rdpdr->devman->devices, (void*)keys[j]); - if (!device_ext || !device_ext->path) + if (!device_ext || !device_ext->path || !device_ext->automount) continue; ConvertFromUnicode(CP_UTF8, 0, device_ext->path, -1, &path, 0, NULL, NULL); @@ -880,6 +893,7 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) drive->Type = RDPDR_DTYP_FILESYSTEM; drive->Path = dev_array[i].path; + drive->automount = TRUE; dev_array[i].path = NULL; name = strrchr(drive->Path, '/') + 1; drive->Name = _strdup(name); @@ -906,6 +920,7 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) } cleanup: + free(keys); for (i = 0; i < size; i++) free(dev_array[i].path); @@ -1069,7 +1084,7 @@ static UINT rdpdr_process_connect(rdpdrPlugin* rdpdr) first_hotplug(rdpdr); if (!(rdpdr->hotplugThread = CreateThread(NULL, 0, - drive_hotplug_thread_func, rdpdr, 0, NULL))) + drive_hotplug_thread_func, rdpdr, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); return ERROR_INTERNAL_ERROR; @@ -1147,6 +1162,7 @@ static UINT rdpdr_send_client_name_request(rdpdrPlugin* rdpdr) if (!s) { + free(computerNameW); WLog_ERR(TAG, "Stream_New failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -1207,7 +1223,7 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, size_t count_pos; DEVICE* device; int keyCount; - ULONG_PTR* pKeys; + ULONG_PTR* pKeys = NULL; s = Stream_New(NULL, 256); if (!s) @@ -1243,6 +1259,8 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, if (!Stream_EnsureRemainingCapacity(s, 20 + data_len)) { + free(pKeys); + Stream_Free(s, TRUE); WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); return ERROR_INVALID_DATA; } @@ -1316,7 +1334,7 @@ static UINT rdpdr_process_init(rdpdrPlugin* rdpdr) int index; int keyCount; DEVICE* device; - ULONG_PTR* pKeys; + ULONG_PTR* pKeys = NULL; UINT error = CHANNEL_RC_OK; pKeys = NULL; keyCount = ListDictionary_GetKeys(rdpdr->devman->devices, &pKeys); @@ -1609,7 +1627,6 @@ static VOID VCAPITYPE rdpdr_virtual_channel_open_event_ex(LPVOID lpUserParam, DW break; case CHANNEL_EVENT_WRITE_COMPLETE: - Stream_Free((wStream*) pData, TRUE); break; case CHANNEL_EVENT_USER: @@ -1709,7 +1726,7 @@ static UINT rdpdr_virtual_channel_event_connected(rdpdrPlugin* rdpdr, } if (!(rdpdr->thread = CreateThread(NULL, 0, - rdpdr_virtual_channel_client_thread, (void*) rdpdr, 0, + rdpdr_virtual_channel_client_thread, (void*) rdpdr, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); @@ -1728,6 +1745,9 @@ static UINT rdpdr_virtual_channel_event_disconnected(rdpdrPlugin* rdpdr) { UINT error; + if (rdpdr->OpenHandle == 0) + return CHANNEL_RC_OK; + if (MessageQueue_PostQuit(rdpdr->queue, 0) && (WaitForSingleObject(rdpdr->thread, INFINITE) == WAIT_FAILED)) { @@ -1846,7 +1866,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP; - strcpy(rdpdr->channelDef.name, "rdpdr"); + sprintf_s(rdpdr->channelDef.name, ARRAYSIZE(rdpdr->channelDef.name), "rdpdr"); rdpdr->sequenceId = 0; pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*) pEntryPoints; diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c index a8e7ec3..5abf8d0 100644 --- a/channels/rdpdr/server/rdpdr_main.c +++ b/channels/rdpdr/server/rdpdr_main.c @@ -563,7 +563,7 @@ static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* { WLog_ERR(TAG, "rdpdr_server_write_general_capability_set failed with error %"PRIu32"!", error); - return error; + goto out; } if (context->supportsDrives) @@ -572,7 +572,7 @@ static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* { WLog_ERR(TAG, "rdpdr_server_write_drive_capability_set failed with error %"PRIu32"!", error); - return error; + goto out; } } @@ -582,7 +582,7 @@ static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* { WLog_ERR(TAG, "rdpdr_server_write_port_capability_set failed with error %"PRIu32"!", error); - return error; + goto out; } } @@ -592,7 +592,7 @@ static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* { WLog_ERR(TAG, "rdpdr_server_write_printer_capability_set failed with error %"PRIu32"!", error); - return error; + goto out; } } @@ -602,7 +602,7 @@ static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* { WLog_ERR(TAG, "rdpdr_server_write_printer_capability_set failed with error %"PRIu32"!", error); - return error; + goto out; } } @@ -612,6 +612,9 @@ static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* (PCHAR) Stream_Buffer(s), Stream_Length(s), &written); Stream_Free(s, TRUE); return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; +out: + Stream_Free(s, TRUE); + return error; } /** @@ -1260,7 +1263,7 @@ static UINT rdpdr_server_start(RdpdrServerContext* context) } if (!(context->priv->Thread = CreateThread(NULL, 0, - rdpdr_server_thread, (void*) context, 0, NULL))) + rdpdr_server_thread, (void*) context, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); CloseHandle(context->priv->StopEvent); @@ -1737,7 +1740,7 @@ static UINT rdpdr_server_drive_create_directory(RdpdrServerContext* context, irp->Callback = rdpdr_server_drive_create_directory_callback1; irp->CallbackData = callbackData; irp->DeviceId = deviceId; - strncpy(irp->PathName, path, sizeof(irp->PathName)); + strncpy(irp->PathName, path, sizeof(irp->PathName) - 1); rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName)); if (!rdpdr_server_enqueue_irp(context, irp)) @@ -1848,7 +1851,7 @@ static UINT rdpdr_server_drive_delete_directory(RdpdrServerContext* context, irp->Callback = rdpdr_server_drive_delete_directory_callback1; irp->CallbackData = callbackData; irp->DeviceId = deviceId; - strncpy(irp->PathName, path, sizeof(irp->PathName)); + strncpy(irp->PathName, path, sizeof(irp->PathName) - 1); rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName)); if (!rdpdr_server_enqueue_irp(context, irp)) @@ -2016,7 +2019,7 @@ static UINT rdpdr_server_drive_query_directory(RdpdrServerContext* context, irp->Callback = rdpdr_server_drive_query_directory_callback1; irp->CallbackData = callbackData; irp->DeviceId = deviceId; - strncpy(irp->PathName, path, sizeof(irp->PathName)); + strncpy(irp->PathName, path, sizeof(irp->PathName) - 1); rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName)); if (!rdpdr_server_enqueue_irp(context, irp)) @@ -2090,7 +2093,7 @@ static UINT rdpdr_server_drive_open_file(RdpdrServerContext* context, irp->Callback = rdpdr_server_drive_open_file_callback; irp->CallbackData = callbackData; irp->DeviceId = deviceId; - strncpy(irp->PathName, path, sizeof(irp->PathName)); + strncpy(irp->PathName, path, sizeof(irp->PathName) - 1); rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName)); if (!rdpdr_server_enqueue_irp(context, irp)) @@ -2417,7 +2420,7 @@ static UINT rdpdr_server_drive_delete_file(RdpdrServerContext* context, irp->Callback = rdpdr_server_drive_delete_file_callback1; irp->CallbackData = callbackData; irp->DeviceId = deviceId; - strncpy(irp->PathName, path, sizeof(irp->PathName)); + strncpy(irp->PathName, path, sizeof(irp->PathName) - 1); rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName)); if (!rdpdr_server_enqueue_irp(context, irp)) @@ -2567,8 +2570,8 @@ static UINT rdpdr_server_drive_rename_file(RdpdrServerContext* context, irp->Callback = rdpdr_server_drive_rename_file_callback1; irp->CallbackData = callbackData; irp->DeviceId = deviceId; - strncpy(irp->PathName, oldPath, sizeof(irp->PathName)); - strncpy(irp->ExtraBuffer, newPath, sizeof(irp->ExtraBuffer)); + strncpy(irp->PathName, oldPath, sizeof(irp->PathName) - 1); + strncpy(irp->ExtraBuffer, newPath, sizeof(irp->ExtraBuffer) - 1); rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName)); rdpdr_server_convert_slashes(irp->ExtraBuffer, sizeof(irp->ExtraBuffer)); diff --git a/channels/rdpgfx/client/rdpgfx_codec.c b/channels/rdpgfx/client/rdpgfx_codec.c index a88c7d0..d2dfbb3 100644 --- a/channels/rdpgfx/client/rdpgfx_codec.c +++ b/channels/rdpgfx/client/rdpgfx_codec.c @@ -139,8 +139,8 @@ static UINT rdpgfx_decode_AVC420(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd wStream* s; RDPGFX_AVC420_BITMAP_STREAM h264; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; - s = Stream_New(cmd->data, cmd->length); + if (!s) { WLog_ERR(TAG, "Stream_New failed!"); @@ -149,6 +149,7 @@ static UINT rdpgfx_decode_AVC420(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd if ((error = rdpgfx_read_h264_metablock(gfx, s, &(h264.meta)))) { + Stream_Free(s, FALSE); WLog_ERR(TAG, "rdpgfx_read_h264_metablock failed with error %"PRIu32"!", error); return error; } @@ -184,8 +185,8 @@ static UINT rdpgfx_decode_AVC444(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd wStream* s; RDPGFX_AVC444_BITMAP_STREAM h264 = { 0 }; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; - s = Stream_New(cmd->data, cmd->length); + if (!s) { WLog_ERR(TAG, "Stream_New failed!"); @@ -197,6 +198,7 @@ static UINT rdpgfx_decode_AVC444(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd error = ERROR_INVALID_DATA; goto fail; } + Stream_Read_UINT32(s, tmp); h264.cbAvc420EncodedBitstream1 = tmp & 0x3FFFFFFFUL; h264.LC = (tmp >> 30UL) & 0x03UL; diff --git a/channels/rdpsnd/CMakeLists.txt b/channels/rdpsnd/CMakeLists.txt index 44a46fe..08b6836 100644 --- a/channels/rdpsnd/CMakeLists.txt +++ b/channels/rdpsnd/CMakeLists.txt @@ -17,6 +17,9 @@ define_channel("rdpsnd") +include_directories(common) +add_subdirectory(common) + if(WITH_CLIENT_CHANNELS) add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) endif() diff --git a/channels/rdpsnd/client/CMakeLists.txt b/channels/rdpsnd/client/CMakeLists.txt index 6e166b2..e66f23a 100644 --- a/channels/rdpsnd/client/CMakeLists.txt +++ b/channels/rdpsnd/client/CMakeLists.txt @@ -23,10 +23,9 @@ set(${MODULE_PREFIX}_SRCS add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntryEx") - - -target_link_libraries(${MODULE_NAME} winpr freerdp ${CMAKE_THREAD_LIBS_INIT}) - +target_link_libraries(${MODULE_NAME} + winpr freerdp ${CMAKE_THREAD_LIBS_INIT} +) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") @@ -57,3 +56,5 @@ endif() if(WITH_OPENSLES) add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "opensles" "") endif() + +add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "fake" "") diff --git a/channels/rdpsnd/client/alsa/rdpsnd_alsa.c b/channels/rdpsnd/client/alsa/rdpsnd_alsa.c index 9ab4222..65f298a 100644 --- a/channels/rdpsnd/client/alsa/rdpsnd_alsa.c +++ b/channels/rdpsnd/client/alsa/rdpsnd_alsa.c @@ -47,22 +47,18 @@ struct rdpsnd_alsa_plugin { rdpsndDevicePlugin device; - int latency; - int wformat; - int block_size; + UINT32 latency; + AUDIO_FORMAT aformat; char* device_name; snd_pcm_t* pcm_handle; snd_mixer_t* mixer_handle; - UINT32 source_rate; + UINT32 actual_rate; - UINT32 wLocalTimeClose; snd_pcm_format_t format; - UINT32 source_channels; UINT32 actual_channels; - int bytes_per_channel; + snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t period_size; - FREERDP_DSP_CONTEXT* dsp_context; }; #define SND_PCM_CHECK(_func, _status) \ @@ -77,33 +73,25 @@ static int rdpsnd_alsa_set_hw_params(rdpsndAlsaPlugin* alsa) int status; snd_pcm_hw_params_t* hw_params; snd_pcm_uframes_t buffer_size_max; - status = snd_pcm_hw_params_malloc(&hw_params); SND_PCM_CHECK("snd_pcm_hw_params_malloc", status); - status = snd_pcm_hw_params_any(alsa->pcm_handle, hw_params); SND_PCM_CHECK("snd_pcm_hw_params_any", status); - /* Set interleaved read/write access */ status = snd_pcm_hw_params_set_access(alsa->pcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); SND_PCM_CHECK("snd_pcm_hw_params_set_access", status); - /* Set sample format */ status = snd_pcm_hw_params_set_format(alsa->pcm_handle, hw_params, alsa->format); SND_PCM_CHECK("snd_pcm_hw_params_set_format", status); - /* Set sample rate */ status = snd_pcm_hw_params_set_rate_near(alsa->pcm_handle, hw_params, &alsa->actual_rate, NULL); SND_PCM_CHECK("snd_pcm_hw_params_set_rate_near", status); - /* Set number of channels */ status = snd_pcm_hw_params_set_channels(alsa->pcm_handle, hw_params, alsa->actual_channels); SND_PCM_CHECK("snd_pcm_hw_params_set_channels", status); - /* Get maximum buffer size */ status = snd_pcm_hw_params_get_buffer_size_max(hw_params, &buffer_size_max); SND_PCM_CHECK("snd_pcm_hw_params_get_buffer_size_max", status); - /** * ALSA Parameters * @@ -122,33 +110,28 @@ static int rdpsnd_alsa_set_hw_params(rdpsndAlsaPlugin* alsa) * Commonly this is (2 * period_size), but some hardware can do 8 periods per buffer. * It is also possible for the buffer size to not be an integer multiple of the period size. */ - int interrupts_per_sec_near = 50; - int bytes_per_sec = (alsa->actual_rate * alsa->bytes_per_channel * alsa->actual_channels); - + int bytes_per_sec = (alsa->actual_rate * alsa->aformat.wBitsPerSample / 8 * alsa->actual_channels); alsa->buffer_size = buffer_size_max; alsa->period_size = (bytes_per_sec / interrupts_per_sec_near); if (alsa->period_size > buffer_size_max) { WLog_ERR(TAG, "Warning: requested sound buffer size %lu, got %lu instead\n", - alsa->buffer_size, buffer_size_max); + alsa->buffer_size, buffer_size_max); alsa->period_size = (buffer_size_max / 8); } /* Set buffer size */ status = snd_pcm_hw_params_set_buffer_size_near(alsa->pcm_handle, hw_params, &alsa->buffer_size); SND_PCM_CHECK("snd_pcm_hw_params_set_buffer_size_near", status); - /* Set period size */ - status = snd_pcm_hw_params_set_period_size_near(alsa->pcm_handle, hw_params, &alsa->period_size, NULL); + status = snd_pcm_hw_params_set_period_size_near(alsa->pcm_handle, hw_params, &alsa->period_size, + NULL); SND_PCM_CHECK("snd_pcm_hw_params_set_period_size_near", status); - status = snd_pcm_hw_params(alsa->pcm_handle, hw_params); SND_PCM_CHECK("snd_pcm_hw_params", status); - snd_pcm_hw_params_free(hw_params); - return 0; } @@ -156,27 +139,21 @@ static int rdpsnd_alsa_set_sw_params(rdpsndAlsaPlugin* alsa) { int status; snd_pcm_sw_params_t* sw_params; - status = snd_pcm_sw_params_malloc(&sw_params); SND_PCM_CHECK("snd_pcm_sw_params_malloc", status); - status = snd_pcm_sw_params_current(alsa->pcm_handle, sw_params); SND_PCM_CHECK("snd_pcm_sw_params_current", status); - - status = snd_pcm_sw_params_set_avail_min(alsa->pcm_handle, sw_params, (alsa->bytes_per_channel * alsa->actual_channels)); + status = snd_pcm_sw_params_set_avail_min(alsa->pcm_handle, sw_params, + (alsa->aformat.nChannels * alsa->actual_channels)); SND_PCM_CHECK("snd_pcm_sw_params_set_avail_min", status); - - status = snd_pcm_sw_params_set_start_threshold(alsa->pcm_handle, sw_params, alsa->block_size); + status = snd_pcm_sw_params_set_start_threshold(alsa->pcm_handle, sw_params, + alsa->aformat.nBlockAlign); SND_PCM_CHECK("snd_pcm_sw_params_set_start_threshold", status); - status = snd_pcm_sw_params(alsa->pcm_handle, sw_params); SND_PCM_CHECK("snd_pcm_sw_params", status); - snd_pcm_sw_params_free(sw_params); - status = snd_pcm_prepare(alsa->pcm_handle); SND_PCM_CHECK("snd_pcm_prepare", status); - return 0; } @@ -185,10 +162,8 @@ static int rdpsnd_alsa_validate_params(rdpsndAlsaPlugin* alsa) int status; snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t period_size; - status = snd_pcm_get_params(alsa->pcm_handle, &buffer_size, &period_size); SND_PCM_CHECK("snd_pcm_get_params", status); - return 0; } @@ -205,15 +180,15 @@ static int rdpsnd_alsa_set_params(rdpsndAlsaPlugin* alsa) return rdpsnd_alsa_validate_params(alsa); } -static BOOL rdpsnd_alsa_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) +static BOOL rdpsnd_alsa_set_format(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, + UINT32 latency) { rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; if (format) { - alsa->source_rate = format->nSamplesPerSec; + alsa->aformat = *format; alsa->actual_rate = format->nSamplesPerSec; - alsa->source_channels = format->nChannels; alsa->actual_channels = format->nChannels; switch (format->wFormatTag) @@ -223,32 +198,40 @@ static BOOL rdpsnd_alsa_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* for { case 8: alsa->format = SND_PCM_FORMAT_S8; - alsa->bytes_per_channel = 1; break; case 16: alsa->format = SND_PCM_FORMAT_S16_LE; - alsa->bytes_per_channel = 2; break; + + default: + return FALSE; } + break; - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - alsa->format = SND_PCM_FORMAT_S16_LE; - alsa->bytes_per_channel = 2; + case WAVE_FORMAT_ALAW: + case WAVE_FORMAT_MULAW: break; + + default: + return FALSE; } - - alsa->wformat = format->wFormatTag; - alsa->block_size = format->nBlockAlign; } alsa->latency = latency; - return (rdpsnd_alsa_set_params(alsa) == 0); } +static void rdpsnd_alsa_close_mixer(rdpsndAlsaPlugin* alsa) +{ + if (alsa && alsa->mixer_handle) + { + snd_mixer_close(alsa->mixer_handle); + alsa->mixer_handle = NULL; + } +} + static BOOL rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa) { int status; @@ -257,40 +240,54 @@ static BOOL rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa) return TRUE; status = snd_mixer_open(&alsa->mixer_handle, 0); + if (status < 0) { WLog_ERR(TAG, "snd_mixer_open failed"); - return FALSE; + goto fail; } status = snd_mixer_attach(alsa->mixer_handle, alsa->device_name); + if (status < 0) { WLog_ERR(TAG, "snd_mixer_attach failed"); - snd_mixer_close(alsa->mixer_handle); - return FALSE; + goto fail; } status = snd_mixer_selem_register(alsa->mixer_handle, NULL, NULL); + if (status < 0) { WLog_ERR(TAG, "snd_mixer_selem_register failed"); - snd_mixer_close(alsa->mixer_handle); - return FALSE; + goto fail; } status = snd_mixer_load(alsa->mixer_handle); + if (status < 0) { WLog_ERR(TAG, "snd_mixer_load failed"); - snd_mixer_close(alsa->mixer_handle); - return FALSE; + goto fail; } return TRUE; +fail: + rdpsnd_alsa_close_mixer(alsa); + return FALSE; } -static BOOL rdpsnd_alsa_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) +static void rdpsnd_alsa_pcm_close(rdpsndAlsaPlugin* alsa) +{ + if (alsa && alsa->pcm_handle) + { + snd_pcm_drain(alsa->pcm_handle); + snd_pcm_close(alsa->pcm_handle); + alsa->pcm_handle = 0; + } +} + +static BOOL rdpsnd_alsa_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, UINT32 latency) { int mode; int status; @@ -301,91 +298,50 @@ static BOOL rdpsnd_alsa_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, i mode = 0; /*mode |= SND_PCM_NONBLOCK;*/ - status = snd_pcm_open(&alsa->pcm_handle, alsa->device_name, SND_PCM_STREAM_PLAYBACK, mode); + if (status < 0) { WLog_ERR(TAG, "snd_pcm_open failed"); return FALSE; } - freerdp_dsp_context_reset_adpcm(alsa->dsp_context); - return rdpsnd_alsa_set_format(device, format, latency) && - rdpsnd_alsa_open_mixer(alsa); + rdpsnd_alsa_open_mixer(alsa); } static void rdpsnd_alsa_close(rdpsndDevicePlugin* device) { - int status; - snd_htimestamp_t tstamp; - snd_pcm_uframes_t frames; rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; - if (!alsa->pcm_handle) + if (!alsa) return; - status = snd_pcm_htimestamp(alsa->pcm_handle, &frames, &tstamp); - - if (status != 0) - frames = 0; - - alsa->wLocalTimeClose = GetTickCount(); - alsa->wLocalTimeClose += (((frames * 1000) / alsa->actual_rate) / alsa->actual_channels); + rdpsnd_alsa_close_mixer(alsa); } static void rdpsnd_alsa_free(rdpsndDevicePlugin* device) { rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; - - if (alsa->pcm_handle) - { - snd_pcm_drain(alsa->pcm_handle); - snd_pcm_close(alsa->pcm_handle); - alsa->pcm_handle = 0; - } - - if (alsa->mixer_handle) - { - snd_mixer_close(alsa->mixer_handle); - alsa->mixer_handle = NULL; - } - + rdpsnd_alsa_pcm_close(alsa); + rdpsnd_alsa_close_mixer(alsa); free(alsa->device_name); - - freerdp_dsp_context_free(alsa->dsp_context); - free(alsa); } -static BOOL rdpsnd_alsa_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT* format) +static BOOL rdpsnd_alsa_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format) { switch (format->wFormatTag) { case WAVE_FORMAT_PCM: if (format->cbSize == 0 && - format->nSamplesPerSec <= 48000 && - (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && - (format->nChannels == 1 || format->nChannels == 2)) + format->nSamplesPerSec <= 48000 && + (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && + (format->nChannels == 1 || format->nChannels == 2)) { return TRUE; } - break; - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - if (format->nSamplesPerSec <= 48000 && - format->wBitsPerSample == 4 && - (format->nChannels == 1 || format->nChannels == 2)) - { - return TRUE; - } - break; - - case WAVE_FORMAT_ALAW: - case WAVE_FORMAT_MULAW: - case WAVE_FORMAT_GSM610: - default: break; } @@ -403,12 +359,11 @@ static UINT32 rdpsnd_alsa_get_volume(rdpsndDevicePlugin* device) UINT16 dwVolumeRight; snd_mixer_elem_t* elem; rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; - dwVolumeLeft = ((50 * 0xFFFF) / 100); /* 50% */ dwVolumeRight = ((50 * 0xFFFF) / 100); /* 50% */ - if (!alsa->mixer_handle) - rdpsnd_alsa_open_mixer(alsa); + if (!rdpsnd_alsa_open_mixer(alsa)) + return 0; for (elem = snd_mixer_first_elem(alsa->mixer_handle); elem; elem = snd_mixer_elem_next(elem)) { @@ -417,16 +372,13 @@ static UINT32 rdpsnd_alsa_get_volume(rdpsndDevicePlugin* device) snd_mixer_selem_get_playback_volume_range(elem, &volume_min, &volume_max); snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, &volume_left); snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, &volume_right); - - dwVolumeLeft = (UINT16) (((volume_left * 0xFFFF) - volume_min) / (volume_max - volume_min)); - dwVolumeRight = (UINT16) (((volume_right * 0xFFFF) - volume_min) / (volume_max - volume_min)); - + dwVolumeLeft = (UINT16)(((volume_left * 0xFFFF) - volume_min) / (volume_max - volume_min)); + dwVolumeRight = (UINT16)(((volume_right * 0xFFFF) - volume_min) / (volume_max - volume_min)); break; } } dwVolume = (dwVolumeLeft << 16) | dwVolumeRight; - return dwVolume; } @@ -441,12 +393,12 @@ static BOOL rdpsnd_alsa_set_volume(rdpsndDevicePlugin* device, UINT32 value) snd_mixer_elem_t* elem; rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; - if (!alsa->mixer_handle && !rdpsnd_alsa_open_mixer(alsa)) - return FALSE; + if (!rdpsnd_alsa_open_mixer(alsa)) + return FALSE; left = (value & 0xFFFF); right = ((value >> 16) & 0xFFFF); - + for (elem = snd_mixer_first_elem(alsa->mixer_handle); elem; elem = snd_mixer_elem_next(elem)) { if (snd_mixer_selem_has_playback_volume(elem)) @@ -454,8 +406,9 @@ static BOOL rdpsnd_alsa_set_volume(rdpsndDevicePlugin* device, UINT32 value) snd_mixer_selem_get_playback_volume_range(elem, &volume_min, &volume_max); volume_left = volume_min + (left * (volume_max - volume_min)) / 0xFFFF; volume_right = volume_min + (right * (volume_max - volume_min)) / 0xFFFF; + if ((snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, volume_left) < 0) || - (snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, volume_right) < 0)) + (snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, volume_right) < 0)) { WLog_ERR(TAG, "error setting the volume\n"); return FALSE; @@ -466,135 +419,47 @@ static BOOL rdpsnd_alsa_set_volume(rdpsndDevicePlugin* device, UINT32 value) return TRUE; } -static BYTE* rdpsnd_alsa_process_audio_sample(rdpsndDevicePlugin* device, BYTE* data, int* size) +static UINT rdpsnd_alsa_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size) { - int frames; - BYTE* srcData; - int srcFrameSize; - int dstFrameSize; - rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; - - if (alsa->wformat == WAVE_FORMAT_ADPCM) - { - alsa->dsp_context->decode_ms_adpcm(alsa->dsp_context, - data, *size, alsa->source_channels, alsa->block_size); - - *size = alsa->dsp_context->adpcm_size; - srcData = alsa->dsp_context->adpcm_buffer; - } - else if (alsa->wformat == WAVE_FORMAT_DVI_ADPCM) - { - alsa->dsp_context->decode_ima_adpcm(alsa->dsp_context, - data, *size, alsa->source_channels, alsa->block_size); - - *size = alsa->dsp_context->adpcm_size; - srcData = alsa->dsp_context->adpcm_buffer; - } - else - { - srcData = data; - } - - srcFrameSize = alsa->source_channels * alsa->bytes_per_channel; - dstFrameSize = alsa->actual_channels * alsa->bytes_per_channel; - - if ((*size % srcFrameSize) != 0) - return NULL; - - if (!((alsa->source_rate == alsa->actual_rate) && (alsa->source_channels == alsa->actual_channels))) - { - alsa->dsp_context->resample(alsa->dsp_context, srcData, alsa->bytes_per_channel, - alsa->source_channels, alsa->source_rate, *size / srcFrameSize, - alsa->actual_channels, alsa->actual_rate); - - frames = alsa->dsp_context->resampled_frames; - - *size = frames * dstFrameSize; - srcData = alsa->dsp_context->resampled_buffer; - } - - data = srcData; - - return data; -} - -static BOOL rdpsnd_alsa_wave_decode(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) -{ - int size; - BYTE* data; - - size = wave->length; - data = rdpsnd_alsa_process_audio_sample(device, wave->data, &size); - - wave->data = (BYTE*) malloc(size); - if (!wave->data) - return FALSE; - CopyMemory(wave->data, data, size); - wave->length = size; - - return TRUE; -} - -static void rdpsnd_alsa_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) -{ - BYTE* data; - int offset; - int length; - int status; + UINT latency; + size_t offset; int frame_size; - UINT32 wCurrentTime; - snd_htimestamp_t tstamp; - snd_pcm_uframes_t frames; rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; - offset = 0; - data = wave->data; - length = wave->length; - frame_size = alsa->actual_channels * alsa->bytes_per_channel; + frame_size = alsa->actual_channels * alsa->aformat.wBitsPerSample / 8; - if (alsa->wLocalTimeClose) + while (offset < size) { - wCurrentTime = GetTickCount(); + snd_pcm_sframes_t status = snd_pcm_writei(alsa->pcm_handle, &data[offset], + (size - offset) / frame_size); - if (snd_pcm_htimestamp(alsa->pcm_handle, &frames, &tstamp) == -EPIPE) - { - if (wCurrentTime > alsa->wLocalTimeClose) - snd_pcm_recover(alsa->pcm_handle, -EPIPE, 1); - } + if (status < 0) + status = snd_pcm_recover(alsa->pcm_handle, status, 0); - alsa->wLocalTimeClose = 0; - } - - while (offset < length) - { - status = snd_pcm_writei(alsa->pcm_handle, &data[offset], (length - offset) / frame_size); - - if (status == -EPIPE) - { - snd_pcm_recover(alsa->pcm_handle, status, 0); - status = 0; - } - else if (status == -EAGAIN) - { - status = 0; - } - else if (status < 0) + if (status < 0) { WLog_ERR(TAG, "status: %d\n", status); - snd_pcm_close(alsa->pcm_handle); - alsa->pcm_handle = NULL; - rdpsnd_alsa_open((rdpsndDevicePlugin*) alsa, NULL, alsa->latency); + rdpsnd_alsa_close(device); + rdpsnd_alsa_open(device, NULL, alsa->latency); break; } offset += status * frame_size; } - free(data); + { + snd_pcm_sframes_t available, delay; + int rc = snd_pcm_avail_delay(alsa->pcm_handle, &available, &delay); - /* From rdpsnd_main.c */ - wave->wTimeStampB = wave->wTimeStampA + wave->wAudioLength + 65; - wave->wLocalTimeB = wave->wLocalTimeA + wave->wAudioLength + 65; + if (rc != 0) + latency = 0; + else if (available == 0) /* Get [ms] from number of samples */ + latency = delay * 1000 / alsa->actual_rate; + else + latency = 0; + } + + return latency + alsa->latency; } static COMMAND_LINE_ARGUMENT_A rdpsnd_alsa_args[] = @@ -614,10 +479,10 @@ static UINT rdpsnd_alsa_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = CommandLineParseArgumentsA(args->argc, args->argv, rdpsnd_alsa_args, flags, + alsa, NULL, NULL); - status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, rdpsnd_alsa_args, flags, alsa, NULL, NULL); if (status < 0) { WLog_ERR(TAG, "CommandLineParseArgumentsA failed!"); @@ -632,14 +497,13 @@ static UINT rdpsnd_alsa_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* continue; CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dev") { alsa->device_name = _strdup(arg->Value); + if (!alsa->device_name) return CHANNEL_RC_NO_MEMORY; } - CommandLineSwitchEnd(arg) } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); @@ -663,8 +527,8 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p ADDIN_ARGV* args; rdpsndAlsaPlugin* alsa; UINT error; - alsa = (rdpsndAlsaPlugin*) calloc(1, sizeof(rdpsndAlsaPlugin)); + if (!alsa) { WLog_ERR(TAG, "calloc failed!"); @@ -673,28 +537,26 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p alsa->device.Open = rdpsnd_alsa_open; alsa->device.FormatSupported = rdpsnd_alsa_format_supported; - alsa->device.SetFormat = rdpsnd_alsa_set_format; alsa->device.GetVolume = rdpsnd_alsa_get_volume; alsa->device.SetVolume = rdpsnd_alsa_set_volume; - alsa->device.WaveDecode = rdpsnd_alsa_wave_decode; - alsa->device.WavePlay = rdpsnd_alsa_wave_play; + alsa->device.Play = rdpsnd_alsa_play; alsa->device.Close = rdpsnd_alsa_close; alsa->device.Free = rdpsnd_alsa_free; - args = pEntryPoints->args; + if (args->argc > 1) { - if ((error = rdpsnd_alsa_parse_addin_args((rdpsndDevicePlugin *) alsa, args))) + if ((error = rdpsnd_alsa_parse_addin_args((rdpsndDevicePlugin*) alsa, args))) { WLog_ERR(TAG, "rdpsnd_alsa_parse_addin_args failed with error %"PRIu32"", error); goto error_parse_args; } } - if (!alsa->device_name) { alsa->device_name = _strdup("default"); + if (!alsa->device_name) { WLog_ERR(TAG, "_strdup failed!"); @@ -704,27 +566,11 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p } alsa->pcm_handle = 0; - alsa->source_rate = 22050; alsa->actual_rate = 22050; alsa->format = SND_PCM_FORMAT_S16_LE; - alsa->source_channels = 2; alsa->actual_channels = 2; - alsa->bytes_per_channel = 2; - - alsa->dsp_context = freerdp_dsp_context_new(); - if (!alsa->dsp_context) - { - WLog_ERR(TAG, "freerdp_dsp_context_new failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto error_dsp_context; - } - pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) alsa); - return CHANNEL_RC_OK; - -error_dsp_context: - freerdp_dsp_context_free(alsa->dsp_context); error_strdup: free(alsa->device_name); error_parse_args: diff --git a/channels/rdpsnd/client/fake/CMakeLists.txt b/channels/rdpsnd/client/fake/CMakeLists.txt new file mode 100644 index 0000000..fd0240a --- /dev/null +++ b/channels/rdpsnd/client/fake/CMakeLists.txt @@ -0,0 +1,33 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2019 Armin Novak +# Copyright 2019 Thincast Technologies GmbH +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +define_channel_client_subsystem("rdpsnd" "fake" "") + +set(${MODULE_PREFIX}_SRCS + rdpsnd_fake.c) + +include_directories(..) + +add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "") + +list(APPEND ${MODULE_PREFIX}_LIBS freerdp) +list(APPEND ${MODULE_PREFIX}_LIBS winpr) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client/Fake") diff --git a/channels/rdpsnd/client/fake/rdpsnd_fake.c b/channels/rdpsnd/client/fake/rdpsnd_fake.c new file mode 100644 index 0000000..51c184b --- /dev/null +++ b/channels/rdpsnd/client/fake/rdpsnd_fake.c @@ -0,0 +1,172 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Audio Output Virtual Channel + * + * Copyright 2019 Armin Novak + * Copyright 2019 Thincast Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include +#include +#include + +#include + +#include "rdpsnd_main.h" + +typedef struct rdpsnd_fake_plugin rdpsndFakePlugin; + +struct rdpsnd_fake_plugin +{ + rdpsndDevicePlugin device; +}; + +static BOOL rdpsnd_fake_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, UINT32 latency) +{ + return TRUE; +} + +static void rdpsnd_fake_close(rdpsndDevicePlugin* device) +{ +} + +static BOOL rdpsnd_fake_set_volume(rdpsndDevicePlugin* device, UINT32 value) +{ + return TRUE; +} + +static void rdpsnd_fake_free(rdpsndDevicePlugin* device) +{ + rdpsndFakePlugin* fake = (rdpsndFakePlugin*) device; + + if (!fake) + return; + + free(fake); +} + +static BOOL rdpsnd_fake_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format) +{ + return TRUE; +} + +static BOOL rdpsnd_fake_set_format(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, + int latency) +{ + return TRUE; +} + +static UINT rdpsnd_fake_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size) +{ + return CHANNEL_RC_OK; +} + +static void rdpsnd_fake_start(rdpsndDevicePlugin* device) +{ +} + +static COMMAND_LINE_ARGUMENT_A rdpsnd_fake_args[] = +{ + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } +}; + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpsnd_fake_parse_addin_args(rdpsndFakePlugin* fake, ADDIN_ARGV* args) +{ + int status; + DWORD flags; + COMMAND_LINE_ARGUMENT_A* arg; + flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = CommandLineParseArgumentsA(args->argc, args->argv, + rdpsnd_fake_args, flags, fake, NULL, NULL); + + if (status < 0) + return ERROR_INVALID_DATA; + + arg = rdpsnd_fake_args; + + do + { + if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) + continue; + + CommandLineSwitchStart(arg) + CommandLineSwitchEnd(arg) + } + while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + + return CHANNEL_RC_OK; +} + +#ifdef BUILTIN_CHANNELS +#define freerdp_rdpsnd_client_subsystem_entry fake_freerdp_rdpsnd_client_subsystem_entry +#else +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry +#endif + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints) +{ + ADDIN_ARGV* args; + rdpsndFakePlugin* fake; + UINT ret; + fake = (rdpsndFakePlugin*) calloc(1, sizeof(rdpsndFakePlugin)); + + if (!fake) + return CHANNEL_RC_NO_MEMORY; + + fake->device.Open = rdpsnd_fake_open; + fake->device.FormatSupported = rdpsnd_fake_format_supported; + fake->device.SetVolume = rdpsnd_fake_set_volume; + fake->device.Play = rdpsnd_fake_play; + fake->device.Start = rdpsnd_fake_start; + fake->device.Close = rdpsnd_fake_close; + fake->device.Free = rdpsnd_fake_free; + args = pEntryPoints->args; + + if (args->argc > 1) + { + ret = rdpsnd_fake_parse_addin_args(fake, args); + + if (ret != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "error parsing arguments"); + goto error; + } + } + + ret = CHANNEL_RC_NO_MEMORY; + pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, &fake->device); + return CHANNEL_RC_OK; +error: + rdpsnd_fake_free(&fake->device); + return ret; +} diff --git a/channels/rdpsnd/client/ios/rdpsnd_ios.c b/channels/rdpsnd/client/ios/rdpsnd_ios.c index 6108def..6431644 100644 --- a/channels/rdpsnd/client/ios/rdpsnd_ios.c +++ b/channels/rdpsnd/client/ios/rdpsnd_ios.c @@ -48,12 +48,12 @@ typedef struct rdpsnd_ios_plugin #define THIS(__ptr) ((rdpsndIOSPlugin*)__ptr) static OSStatus rdpsnd_ios_render_cb( - void *inRefCon, - AudioUnitRenderActionFlags __unused *ioActionFlags, - const AudioTimeStamp __unused *inTimeStamp, - UInt32 inBusNumber, - UInt32 __unused inNumberFrames, - AudioBufferList *ioData + void* inRefCon, + AudioUnitRenderActionFlags __unused* ioActionFlags, + const AudioTimeStamp __unused* inTimeStamp, + UInt32 inBusNumber, + UInt32 __unused inNumberFrames, + AudioBufferList* ioData ) { unsigned int i; @@ -63,21 +63,19 @@ static OSStatus rdpsnd_ios_render_cb( return noErr; } - rdpsndIOSPlugin *p = THIS(inRefCon); + rdpsndIOSPlugin* p = THIS(inRefCon); for (i = 0; i < ioData->mNumberBuffers; i++) { AudioBuffer* target_buffer = &ioData->mBuffers[i]; - int32_t available_bytes = 0; - const void *buffer = TPCircularBufferTail(&p->buffer, &available_bytes); + const void* buffer = TPCircularBufferTail(&p->buffer, &available_bytes); + if (buffer != NULL && available_bytes > 0) { const int bytes_to_copy = MIN((int32_t)target_buffer->mDataByteSize, available_bytes); - memcpy(target_buffer->mData, buffer, bytes_to_copy); target_buffer->mDataByteSize = bytes_to_copy; - TPCircularBufferConsume(&p->buffer, bytes_to_copy); } else @@ -97,10 +95,12 @@ static BOOL rdpsnd_ios_format_supported(rdpsndDevicePlugin* __unused device, AUD { return 1; } + return 0; } -static BOOL rdpsnd_ios_set_format(rdpsndDevicePlugin* __unused device, AUDIO_FORMAT* __unused format, int __unused latency) +static BOOL rdpsnd_ios_set_format(rdpsndDevicePlugin* __unused device, + AUDIO_FORMAT* __unused format, int __unused latency) { return TRUE; } @@ -112,7 +112,7 @@ static BOOL rdpsnd_ios_set_volume(rdpsndDevicePlugin* __unused device, UINT32 __ static void rdpsnd_ios_start(rdpsndDevicePlugin* device) { - rdpsndIOSPlugin *p = THIS(device); + rdpsndIOSPlugin* p = THIS(device); /* If this device is not playing... */ if (!p->is_playing) @@ -120,6 +120,7 @@ static void rdpsnd_ios_start(rdpsndDevicePlugin* device) /* Start the device. */ int32_t available_bytes = 0; TPCircularBufferTail(&p->buffer, &available_bytes); + if (available_bytes > 0) { p->is_playing = 1; @@ -130,7 +131,7 @@ static void rdpsnd_ios_start(rdpsndDevicePlugin* device) static void rdpsnd_ios_stop(rdpsndDevicePlugin* __unused device) { - rdpsndIOSPlugin *p = THIS(device); + rdpsndIOSPlugin* p = THIS(device); /* If the device is playing... */ if (p->is_playing) @@ -138,28 +139,26 @@ static void rdpsnd_ios_stop(rdpsndDevicePlugin* __unused device) /* Stop the device. */ AudioOutputUnitStop(p->audio_unit); p->is_playing = 0; - /* Free all buffers. */ TPCircularBufferClear(&p->buffer); } } -static void rdpsnd_ios_play(rdpsndDevicePlugin* device, BYTE* data, int size) +static UINT rdpsnd_ios_play(rdpsndDevicePlugin* device, BYTE* data, int size) { - rdpsndIOSPlugin *p = THIS(device); - + rdpsndIOSPlugin* p = THIS(device); const BOOL ok = TPCircularBufferProduceBytes(&p->buffer, data, size); + if (!ok) - { - return; - } + return 0; rdpsnd_ios_start(device); + return 10; /* TODO: Get real latencry in [ms] */ } static BOOL rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int __unused latency) { - rdpsndIOSPlugin *p = THIS(device); + rdpsndIOSPlugin* p = THIS(device); if (p->is_opened) return TRUE; @@ -171,13 +170,14 @@ static BOOL rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in desc.componentSubType = kAudioUnitSubType_RemoteIO; desc.componentFlags = 0; desc.componentFlagsMask = 0; - AudioComponent audioComponent = AudioComponentFindNext(NULL, &desc); + if (audioComponent == NULL) return FALSE; /* Open the audio unit. */ OSStatus status = AudioComponentInstanceNew(audioComponent, &p->audio_unit); + if (status != 0) return FALSE; @@ -191,14 +191,14 @@ static BOOL rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in audioFormat.mBitsPerChannel = format->wBitsPerSample; audioFormat.mBytesPerFrame = (format->wBitsPerSample * format->nChannels) / 8; audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame * audioFormat.mFramesPerPacket; - status = AudioUnitSetProperty( - p->audio_unit, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, - 0, - &audioFormat, - sizeof(audioFormat)); + p->audio_unit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 0, + &audioFormat, + sizeof(audioFormat)); + if (status != 0) { AudioComponentInstanceDispose(p->audio_unit); @@ -211,12 +211,13 @@ static BOOL rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in callbackStruct.inputProc = rdpsnd_ios_render_cb; callbackStruct.inputProcRefCon = p; status = AudioUnitSetProperty( - p->audio_unit, - kAudioUnitProperty_SetRenderCallback, - kAudioUnitScope_Input, - 0, - &callbackStruct, - sizeof(callbackStruct)); + p->audio_unit, + kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Input, + 0, + &callbackStruct, + sizeof(callbackStruct)); + if (status != 0) { AudioComponentInstanceDispose(p->audio_unit); @@ -226,6 +227,7 @@ static BOOL rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in /* Initialize the AudioUnit. */ status = AudioUnitInitialize(p->audio_unit); + if (status != 0) { AudioComponentInstanceDispose(p->audio_unit); @@ -235,6 +237,7 @@ static BOOL rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in /* Allocate the circular buffer. */ const BOOL ok = TPCircularBufferInit(&p->buffer, CIRCULAR_BUFFER_SIZE); + if (!ok) { AudioUnitUninitialize(p->audio_unit); @@ -249,8 +252,7 @@ static BOOL rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in static void rdpsnd_ios_close(rdpsndDevicePlugin* device) { - rdpsndIOSPlugin *p = THIS(device); - + rdpsndIOSPlugin* p = THIS(device); /* Make sure the device is stopped. */ rdpsnd_ios_stop(device); @@ -262,7 +264,6 @@ static void rdpsnd_ios_close(rdpsndDevicePlugin* device) AudioComponentInstanceDispose(p->audio_unit); p->audio_unit = NULL; p->is_opened = 0; - /* Destroy the circular buffer. */ TPCircularBufferCleanup(&p->buffer); } @@ -270,11 +271,9 @@ static void rdpsnd_ios_close(rdpsndDevicePlugin* device) static void rdpsnd_ios_free(rdpsndDevicePlugin* device) { - rdpsndIOSPlugin *p = THIS(device); - + rdpsndIOSPlugin* p = THIS(device); /* Ensure the device is closed. */ rdpsnd_ios_close(device); - /* Free memory associated with the device. */ free(p); } @@ -305,8 +304,6 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p p->device.Start = rdpsnd_ios_start; p->device.Close = rdpsnd_ios_close; p->device.Free = rdpsnd_ios_free; - pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)p); - return CHANNEL_RC_OK; } diff --git a/channels/rdpsnd/client/mac/rdpsnd_mac.c b/channels/rdpsnd/client/mac/rdpsnd_mac.c index 93e448f..3bb2902 100644 --- a/channels/rdpsnd/client/mac/rdpsnd_mac.c +++ b/channels/rdpsnd/client/mac/rdpsnd_mac.c @@ -32,7 +32,6 @@ #include #include -#include #define __COREFOUNDATION_CFPLUGINCOM__ 1 #define IUNKNOWN_C_GUTS void *_reserved; void* QueryInterface; void* AddRef; void* Release @@ -51,144 +50,176 @@ struct rdpsnd_mac_plugin BOOL isOpen; BOOL isPlaying; - + UINT32 latency; AUDIO_FORMAT format; size_t lastAudioBufferIndex; size_t audioBufferIndex; - + AudioQueueRef audioQueue; AudioStreamBasicDescription audioFormat; AudioQueueBufferRef audioBuffers[MAC_AUDIO_QUEUE_NUM_BUFFERS]; - - Float64 lastStartTime; - - int wformat; - int block_size; - FREERDP_DSP_CONTEXT* dsp_context; }; typedef struct rdpsnd_mac_plugin rdpsndMacPlugin; -static void mac_audio_queue_output_cb(void* inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) +static void mac_audio_queue_output_cb(void* inUserData, AudioQueueRef inAQ, + AudioQueueBufferRef inBuffer) { rdpsndMacPlugin* mac = (rdpsndMacPlugin*)inUserData; - if (inBuffer == mac->audioBuffers[mac->lastAudioBufferIndex]) { + if (inBuffer == mac->audioBuffers[mac->lastAudioBufferIndex]) + { AudioQueuePause(mac->audioQueue); mac->isPlaying = FALSE; } } -static BOOL rdpsnd_mac_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) +static BOOL rdpsnd_mac_set_format(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, + UINT32 latency) { rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; - mac->latency = (UINT32) latency; CopyMemory(&(mac->format), format, sizeof(AUDIO_FORMAT)); - mac->audioFormat.mSampleRate = format->nSamplesPerSec; mac->audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; mac->audioFormat.mFramesPerPacket = 1; mac->audioFormat.mChannelsPerFrame = format->nChannels; mac->audioFormat.mBitsPerChannel = format->wBitsPerSample; - mac->audioFormat.mBytesPerFrame = (format->wBitsPerSample * format->nChannels) / 8; - mac->audioFormat.mBytesPerPacket = format->nBlockAlign; + mac->audioFormat.mBytesPerFrame = mac->audioFormat.mBitsPerChannel * + mac->audioFormat.mChannelsPerFrame / 8; + mac->audioFormat.mBytesPerPacket = mac->audioFormat.mBytesPerFrame * + mac->audioFormat.mFramesPerPacket; mac->audioFormat.mReserved = 0; - + switch (format->wFormatTag) { case WAVE_FORMAT_ALAW: mac->audioFormat.mFormatID = kAudioFormatALaw; break; - + case WAVE_FORMAT_MULAW: mac->audioFormat.mFormatID = kAudioFormatULaw; break; - + case WAVE_FORMAT_PCM: mac->audioFormat.mFormatID = kAudioFormatLinearPCM; break; - - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - mac->audioFormat.mFormatID = kAudioFormatLinearPCM; - mac->audioFormat.mBitsPerChannel = 16; - mac->audioFormat.mBytesPerFrame = (16 * format->nChannels) / 8; - mac->audioFormat.mBytesPerPacket = mac->audioFormat.mFramesPerPacket * mac->audioFormat.mBytesPerFrame; - break; - - case WAVE_FORMAT_GSM610: - mac->audioFormat.mFormatID = kAudioFormatMicrosoftGSM; - break; - + default: - break; + return FALSE; } - - mac->wformat = format->wFormatTag; - mac->block_size = format->nBlockAlign; - - rdpsnd_print_audio_format(format); + + audio_format_print(WLog_Get(TAG), WLOG_DEBUG, format); return TRUE; } -static BOOL rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) +static char* FormatError(OSStatus st) +{ + switch (st) + { + case kAudioFileUnspecifiedError: + return "kAudioFileUnspecifiedError"; + + case kAudioFileUnsupportedFileTypeError: + return "kAudioFileUnsupportedFileTypeError"; + + case kAudioFileUnsupportedDataFormatError: + return "kAudioFileUnsupportedDataFormatError"; + + case kAudioFileUnsupportedPropertyError: + return "kAudioFileUnsupportedPropertyError"; + + case kAudioFileBadPropertySizeError: + return "kAudioFileBadPropertySizeError"; + + case kAudioFilePermissionsError: + return "kAudioFilePermissionsError"; + + case kAudioFileNotOptimizedError: + return "kAudioFileNotOptimizedError"; + + case kAudioFileInvalidChunkError: + return "kAudioFileInvalidChunkError"; + + case kAudioFileDoesNotAllow64BitDataSizeError: + return "kAudioFileDoesNotAllow64BitDataSizeError"; + + case kAudioFileInvalidPacketOffsetError: + return "kAudioFileInvalidPacketOffsetError"; + + case kAudioFileInvalidFileError: + return "kAudioFileInvalidFileError"; + + case kAudioFileOperationNotSupportedError: + return "kAudioFileOperationNotSupportedError"; + + case kAudioFileNotOpenError: + return "kAudioFileNotOpenError"; + + case kAudioFileEndOfFileError: + return "kAudioFileEndOfFileError"; + + case kAudioFilePositionError: + return "kAudioFilePositionError"; + + case kAudioFileFileNotFoundError: + return "kAudioFileFileNotFoundError"; + + default: + return "unknown error"; + } +} + +static BOOL rdpsnd_mac_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, UINT32 latency) { int index; OSStatus status; - rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; - + if (mac->isOpen) return TRUE; - + mac->audioBufferIndex = 0; - - if (!device->SetFormat(device, format, 0)) - { - WLog_ERR(TAG, "SetFormat failure\n"); + + if (!rdpsnd_mac_set_format(device, format, latency)) return FALSE; - } - - freerdp_dsp_context_reset_adpcm(mac->dsp_context); status = AudioQueueNewOutput(&(mac->audioFormat), - mac_audio_queue_output_cb, mac, - NULL, NULL, 0, &(mac->audioQueue)); - + mac_audio_queue_output_cb, mac, + NULL, NULL, 0, &(mac->audioQueue)); + if (status != 0) { - WLog_ERR(TAG, "AudioQueueNewOutput failure\n"); + const char* err = FormatError(status); + WLog_ERR(TAG, "AudioQueueNewOutput failure %s", err); return FALSE; } - + UInt32 DecodeBufferSizeFrames; UInt32 propertySize = sizeof(DecodeBufferSizeFrames); - status = AudioQueueGetProperty(mac->audioQueue, - kAudioQueueProperty_DecodeBufferSizeFrames, - &DecodeBufferSizeFrames, - &propertySize); - + kAudioQueueProperty_DecodeBufferSizeFrames, + &DecodeBufferSizeFrames, + &propertySize); + if (status != 0) { WLog_DBG(TAG, "AudioQueueGetProperty failure: kAudioQueueProperty_DecodeBufferSizeFrames\n"); return FALSE; } - + for (index = 0; index < MAC_AUDIO_QUEUE_NUM_BUFFERS; index++) { - status = AudioQueueAllocateBuffer(mac->audioQueue, MAC_AUDIO_QUEUE_BUFFER_SIZE, &mac->audioBuffers[index]); - + status = AudioQueueAllocateBuffer(mac->audioQueue, MAC_AUDIO_QUEUE_BUFFER_SIZE, + &mac->audioBuffers[index]); + if (status != 0) { WLog_ERR(TAG, "AudioQueueAllocateBuffer failed\n"); return FALSE; } } - - mac->lastStartTime = 0; - + mac->isOpen = TRUE; return TRUE; } @@ -196,14 +227,13 @@ static BOOL rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in static void rdpsnd_mac_close(rdpsndDevicePlugin* device) { rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; - + if (mac->isOpen) { size_t index; mac->isOpen = FALSE; - AudioQueueStop(mac->audioQueue, true); - + for (index = 0; index < MAC_AUDIO_QUEUE_NUM_BUFFERS; index++) { AudioQueueFreeBuffer(mac->audioQueue, mac->audioBuffers[index]); @@ -211,7 +241,6 @@ static void rdpsnd_mac_close(rdpsndDevicePlugin* device) AudioQueueDispose(mac->audioQueue, true); mac->audioQueue = NULL; - mac->isPlaying = FALSE; } } @@ -219,29 +248,22 @@ static void rdpsnd_mac_close(rdpsndDevicePlugin* device) static void rdpsnd_mac_free(rdpsndDevicePlugin* device) { rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; - device->Close(device); - - freerdp_dsp_context_free(mac->dsp_context); - free(mac); } -static BOOL rdpsnd_mac_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT* format) +static BOOL rdpsnd_mac_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format) { switch (format->wFormatTag) { case WAVE_FORMAT_PCM: case WAVE_FORMAT_ALAW: case WAVE_FORMAT_MULAW: - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: return TRUE; - case WAVE_FORMAT_GSM610: + + default: return FALSE; } - - return FALSE; } static BOOL rdpsnd_mac_set_volume(rdpsndDevicePlugin* device, UINT32 value) @@ -251,17 +273,15 @@ static BOOL rdpsnd_mac_set_volume(rdpsndDevicePlugin* device, UINT32 value) UINT16 volumeLeft; UINT16 volumeRight; rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; - + if (!mac->audioQueue) return FALSE; - + volumeLeft = (value & 0xFFFF); volumeRight = ((value >> 16) & 0xFFFF); - fVolume = ((float) volumeLeft) / 65535.0; - status = AudioQueueSetParameter(mac->audioQueue, kAudioQueueParam_Volume, fVolume); - + if (status != 0) { WLog_ERR(TAG, "AudioQueueSetParameter kAudioQueueParam_Volume failed: %f\n", fVolume); @@ -274,87 +294,47 @@ static BOOL rdpsnd_mac_set_volume(rdpsndDevicePlugin* device, UINT32 value) static void rdpsnd_mac_start(rdpsndDevicePlugin* device) { rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; - + if (!mac->isPlaying) { OSStatus status; - + if (!mac->audioQueue) return; - + status = AudioQueueStart(mac->audioQueue, NULL); - + if (status != 0) { WLog_ERR(TAG, "AudioQueueStart failed\n"); } - + mac->isPlaying = TRUE; } } -static BOOL rdpsnd_mac_wave_decode(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) +static UINT rdpsnd_mac_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size) { - int length; - BYTE* data; - rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; - - if (mac->wformat == WAVE_FORMAT_ADPCM) - { - mac->dsp_context->decode_ms_adpcm(mac->dsp_context, wave->data, wave->length, mac->format.nChannels, mac->block_size); - length = mac->dsp_context->adpcm_size; - data = mac->dsp_context->adpcm_buffer; - } - else if (mac->wformat == WAVE_FORMAT_DVI_ADPCM) - { - mac->dsp_context->decode_ima_adpcm(mac->dsp_context, wave->data, wave->length, mac->format.nChannels, mac->block_size); - length = mac->dsp_context->adpcm_size; - data = mac->dsp_context->adpcm_buffer; - } - else - { - length = wave->length; - data = wave->data; - } - - wave->data = (BYTE*) malloc(length); - CopyMemory(wave->data, data, length); - wave->length = length; - - return TRUE; -} - -static void rdpsnd_mac_waveplay(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) -{ - int length; + size_t length; AudioQueueBufferRef audioBuffer; AudioTimeStamp outActualStartTime; rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; - + if (!mac->isOpen) - return; + return 0; audioBuffer = mac->audioBuffers[mac->audioBufferIndex]; - - length = wave->length > audioBuffer->mAudioDataBytesCapacity ? audioBuffer->mAudioDataBytesCapacity : wave->length; - - CopyMemory(audioBuffer->mAudioData, wave->data, length); - free(wave->data); - wave->data = NULL; + length = size > audioBuffer->mAudioDataBytesCapacity ? audioBuffer->mAudioDataBytesCapacity : size; + CopyMemory(audioBuffer->mAudioData, data, length); audioBuffer->mAudioDataByteSize = length; - audioBuffer->mUserData = wave; - - AudioQueueEnqueueBufferWithParameters(mac->audioQueue, audioBuffer, 0, 0, 0, 0, 0, NULL, NULL, &outActualStartTime); - UInt64 startTimeDelta = (outActualStartTime.mSampleTime - mac->lastStartTime) / 100.0; - wave->wLocalTimeB = wave->wLocalTimeA + startTimeDelta + wave->wAudioLength; - wave->wTimeStampB = wave->wTimeStampA + wave->wLocalTimeB - wave->wLocalTimeA; - mac->lastStartTime = outActualStartTime.mSampleTime; - + audioBuffer->mUserData = mac; + AudioQueueEnqueueBufferWithParameters(mac->audioQueue, audioBuffer, 0, 0, 0, 0, 0, NULL, NULL, + &outActualStartTime); mac->lastAudioBufferIndex = mac->audioBufferIndex; mac->audioBufferIndex++; mac->audioBufferIndex %= MAC_AUDIO_QUEUE_NUM_BUFFERS; - - device->Start(device); + rdpsnd_mac_start(device); + return 10; /* TODO: Get real latencry in [ms] */ } #ifdef BUILTIN_CHANNELS @@ -371,25 +351,17 @@ static void rdpsnd_mac_waveplay(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints) { rdpsndMacPlugin* mac; - mac = (rdpsndMacPlugin*) calloc(1, sizeof(rdpsndMacPlugin)); - + if (!mac) return CHANNEL_RC_NO_MEMORY; - + mac->device.Open = rdpsnd_mac_open; mac->device.FormatSupported = rdpsnd_mac_format_supported; - mac->device.SetFormat = rdpsnd_mac_set_format; mac->device.SetVolume = rdpsnd_mac_set_volume; - mac->device.WaveDecode = rdpsnd_mac_wave_decode; - mac->device.WavePlay = rdpsnd_mac_waveplay; - mac->device.Start = rdpsnd_mac_start; + mac->device.Play = rdpsnd_mac_play; mac->device.Close = rdpsnd_mac_close; mac->device.Free = rdpsnd_mac_free; - - mac->dsp_context = freerdp_dsp_context_new(); - pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) mac); - return CHANNEL_RC_OK; } diff --git a/channels/rdpsnd/client/opensles/rdpsnd_opensles.c b/channels/rdpsnd/client/opensles/rdpsnd_opensles.c index 2346855..26ea455 100644 --- a/channels/rdpsnd/client/opensles/rdpsnd_opensles.c +++ b/channels/rdpsnd/client/opensles/rdpsnd_opensles.c @@ -36,7 +36,6 @@ #include #include -#include #include #include "opensl_io.h" @@ -48,7 +47,7 @@ struct rdpsnd_opensles_plugin { rdpsndDevicePlugin device; - int latency; + UINT32 latency; int wformat; int block_size; char* device_name; @@ -60,7 +59,6 @@ struct rdpsnd_opensles_plugin UINT32 rate; UINT32 channels; int format; - FREERDP_DSP_CONTEXT* dsp_context; }; static int rdpsnd_opensles_volume_to_millibel(unsigned short level, int max) @@ -91,9 +89,6 @@ static bool rdpsnd_opensles_check_handle(const rdpsndopenslesPlugin* hdl) rc = false; else { - if (!hdl->dsp_context) - rc = false; - if (!hdl->stream) rc = false; } @@ -120,11 +115,11 @@ static int rdpsnd_opensles_set_params(rdpsndopenslesPlugin* opensles) } static BOOL rdpsnd_opensles_set_format(rdpsndDevicePlugin* device, - AUDIO_FORMAT* format, int latency) + const AUDIO_FORMAT* format, UINT32 latency) { rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; rdpsnd_opensles_check_handle(opensles); - DEBUG_SND("opensles=%p format=%p, latency=%d", (void*) opensles, (void*) format, latency); + DEBUG_SND("opensles=%p format=%p, latency=%"PRIu32, (void*) opensles, (void*) format, latency); if (format) { @@ -143,11 +138,11 @@ static BOOL rdpsnd_opensles_set_format(rdpsndDevicePlugin* device, } static BOOL rdpsnd_opensles_open(rdpsndDevicePlugin* device, - AUDIO_FORMAT* format, int latency) + const AUDIO_FORMAT* format, UINT32 latency) { rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; - DEBUG_SND("opensles=%p format=%p, latency=%d, rate=%"PRIu32"", - (void*) opensles, (void*) format, latency, opensles->rate); + DEBUG_SND("opensles=%p format=%p, latency=%"PRIu32", rate=%"PRIu32"", + (void*) opensles, (void*) format, latency, opensles->rate); if (rdpsnd_opensles_check_handle(opensles)) return TRUE; @@ -161,8 +156,7 @@ static BOOL rdpsnd_opensles_open(rdpsndDevicePlugin* device, else rdpsnd_opensles_set_volume(device, opensles->volume); - rdpsnd_opensles_set_format(device, format, latency); - return TRUE; + return rdpsnd_opensles_set_format(device, format, latency); } static void rdpsnd_opensles_close(rdpsndDevicePlugin* device) @@ -184,13 +178,11 @@ static void rdpsnd_opensles_free(rdpsndDevicePlugin* device) assert(opensles); assert(opensles->device_name); free(opensles->device_name); - assert(opensles->dsp_context); - freerdp_dsp_context_free(opensles->dsp_context); free(opensles); } static BOOL rdpsnd_opensles_format_supported(rdpsndDevicePlugin* device, - AUDIO_FORMAT* format) + const AUDIO_FORMAT* format) { DEBUG_SND("format=%"PRIu16", cbsize=%"PRIu16", samples=%"PRIu32", bits=%"PRIu16", channels=%"PRIu16", align=%"PRIu16"", format->wFormatTag, format->cbSize, format->nSamplesPerSec, @@ -211,20 +203,6 @@ static BOOL rdpsnd_opensles_format_supported(rdpsndDevicePlugin* device, break; - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - if (format->nSamplesPerSec <= 48000 && - format->wBitsPerSample == 4 && - (format->nChannels == 1 || format->nChannels == 2)) - { - return TRUE; - } - - break; - - case WAVE_FORMAT_ALAW: - case WAVE_FORMAT_MULAW: - case WAVE_FORMAT_GSM610: default: break; } @@ -283,46 +261,22 @@ static BOOL rdpsnd_opensles_set_volume(rdpsndDevicePlugin* device, return TRUE; } -static void rdpsnd_opensles_play(rdpsndDevicePlugin* device, - BYTE* data, int size) +static UINT rdpsnd_opensles_play(rdpsndDevicePlugin* device, + const BYTE* data, size_t size) { union { - BYTE* b; - short* s; + const BYTE* b; + const short* s; } src; int ret; rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; DEBUG_SND("opensles=%p, data=%p, size=%d", (void*) opensles, (void*) data, size); if (!rdpsnd_opensles_check_handle(opensles)) - return; - - if (opensles->format == WAVE_FORMAT_ADPCM) - { - DEBUG_SND("dsp_context=%p, channels=%"PRIu32", block_size=%d", - (void*) opensles->dsp_context, opensles->channels, opensles->block_size); - - opensles->dsp_context->decode_ms_adpcm(opensles->dsp_context, - data, size, opensles->channels, opensles->block_size); - size = opensles->dsp_context->adpcm_size; - src.b = opensles->dsp_context->adpcm_buffer; - } - else if (opensles->format == WAVE_FORMAT_DVI_ADPCM) - { - DEBUG_SND("dsp_context=%p, channels=%"PRIu32", block_size=%d", - (void*) opensles->dsp_context, opensles->channels, opensles->block_size); - - opensles->dsp_context->decode_ima_adpcm(opensles->dsp_context, - data, size, opensles->channels, opensles->block_size); - size = opensles->dsp_context->adpcm_size; - src.b = opensles->dsp_context->adpcm_buffer; - } - else - { - src.b = data; - } + return 0; + src.b = data; DEBUG_SND("size=%d, src=%p", size, (void*) src.b); assert(0 == size % 2); assert(size > 0); @@ -331,6 +285,8 @@ static void rdpsnd_opensles_play(rdpsndDevicePlugin* device, if (ret < 0) WLog_ERR(TAG, "android_AudioOut failed (%d)", ret); + + return 10; /* TODO: Get real latencry in [ms] */ } static void rdpsnd_opensles_start(rdpsndDevicePlugin* device) @@ -361,7 +317,7 @@ static int rdpsnd_opensles_parse_addin_args(rdpsndDevicePlugin* device, DEBUG_SND("opensles=%p, args=%p", (void*) opensles, (void*) args); flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, + status = CommandLineParseArgumentsA(args->argc, args->argv, rdpsnd_opensles_args, flags, opensles, NULL, NULL); if (status < 0) @@ -416,7 +372,6 @@ UINT freerdp_rdpsnd_client_subsystem_entry( opensles->device.Open = rdpsnd_opensles_open; opensles->device.FormatSupported = rdpsnd_opensles_format_supported; - opensles->device.SetFormat = rdpsnd_opensles_set_format; opensles->device.GetVolume = rdpsnd_opensles_get_volume; opensles->device.SetVolume = rdpsnd_opensles_set_volume; opensles->device.Start = rdpsnd_opensles_start; @@ -440,20 +395,10 @@ UINT freerdp_rdpsnd_client_subsystem_entry( opensles->rate = 44100; opensles->channels = 2; opensles->format = WAVE_FORMAT_ADPCM; - opensles->dsp_context = freerdp_dsp_context_new(); - - if (!opensles->dsp_context) - { - error = CHANNEL_RC_NO_MEMORY; - goto out_dsp_new; - } - pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) opensles); DEBUG_SND("success"); return CHANNEL_RC_OK; -out_dsp_new: - free(opensles->device_name); outstrdup: free(opensles); return error; diff --git a/channels/rdpsnd/client/oss/rdpsnd_oss.c b/channels/rdpsnd/client/oss/rdpsnd_oss.c index 9a9d103..ff402c9 100644 --- a/channels/rdpsnd/client/oss/rdpsnd_oss.c +++ b/channels/rdpsnd/client/oss/rdpsnd_oss.c @@ -47,7 +47,6 @@ #include #include -#include #include #include "rdpsnd_main.h" @@ -64,10 +63,8 @@ struct rdpsnd_oss_plugin int supported_formats; - int latency; + UINT32 latency; AUDIO_FORMAT format; - - FREERDP_DSP_CONTEXT* dsp_context; }; #define OSS_LOG_ERR(_text, _error) \ @@ -77,7 +74,7 @@ struct rdpsnd_oss_plugin } -static int rdpsnd_oss_get_format(AUDIO_FORMAT* format) +static int rdpsnd_oss_get_format(const AUDIO_FORMAT* format) { switch (format->wFormatTag) { @@ -95,21 +92,15 @@ static int rdpsnd_oss_get_format(AUDIO_FORMAT* format) case WAVE_FORMAT_ALAW: return AFMT_A_LAW; -#if 0 /* This does not work on my desktop. */ case WAVE_FORMAT_MULAW: return AFMT_MU_LAW; -#endif - - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - return AFMT_S16_LE; } return 0; } -static BOOL rdpsnd_oss_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT* format) +static BOOL rdpsnd_oss_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format) { int req_fmt = 0; rdpsndOssPlugin* oss = (rdpsndOssPlugin*)device; @@ -128,14 +119,12 @@ static BOOL rdpsnd_oss_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT break; - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - if (format->nSamplesPerSec > 48000 || - format->wBitsPerSample != 4 || - (format->nChannels != 1 && format->nChannels != 2)) - return FALSE; - + case WAVE_FORMAT_MULAW: + case WAVE_FORMAT_ALAW: break; + + default: + return FALSE; } req_fmt = rdpsnd_oss_get_format(format); @@ -155,7 +144,8 @@ static BOOL rdpsnd_oss_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT return TRUE; } -static BOOL rdpsnd_oss_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) +static BOOL rdpsnd_oss_set_format(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, + UINT32 latency) { int tmp; rdpsndOssPlugin* oss = (rdpsndOssPlugin*)device; @@ -227,7 +217,7 @@ static void rdpsnd_oss_open_mixer(rdpsndOssPlugin* oss) } } -static BOOL rdpsnd_oss_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) +static BOOL rdpsnd_oss_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, UINT32 latency) { char dev_name[PATH_MAX] = "/dev/dsp"; rdpsndOssPlugin* oss = (rdpsndOssPlugin*)device; @@ -272,7 +262,6 @@ static BOOL rdpsnd_oss_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in return FALSE; } - freerdp_dsp_context_reset_adpcm(oss->dsp_context); rdpsnd_oss_set_format(device, format, latency); rdpsnd_oss_open_mixer(oss); return TRUE; @@ -308,7 +297,6 @@ static void rdpsnd_oss_free(rdpsndDevicePlugin* device) return; rdpsnd_oss_close(device); - freerdp_dsp_context_free(oss->dsp_context); free(oss); } @@ -370,68 +358,36 @@ static BOOL rdpsnd_oss_set_volume(rdpsndDevicePlugin* device, UINT32 value) return TRUE; } -static BOOL rdpsnd_oss_wave_decode(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) +static UINT rdpsnd_oss_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size) { rdpsndOssPlugin* oss = (rdpsndOssPlugin*)device; - if (device == NULL || wave == NULL) - return FALSE; + if (device == NULL || oss->mixer_handle == -1) + return 0; - switch (oss->format.wFormatTag) + while (size > 0) { - case WAVE_FORMAT_ADPCM: - oss->dsp_context->decode_ms_adpcm(oss->dsp_context, - wave->data, wave->length, oss->format.nChannels, oss->format.nBlockAlign); - wave->length = oss->dsp_context->adpcm_size; - wave->data = oss->dsp_context->adpcm_buffer; - break; - - case WAVE_FORMAT_DVI_ADPCM: - oss->dsp_context->decode_ima_adpcm(oss->dsp_context, - wave->data, wave->length, oss->format.nChannels, oss->format.nBlockAlign); - wave->length = oss->dsp_context->adpcm_size; - wave->data = oss->dsp_context->adpcm_buffer; - break; - } - - return TRUE; -} - -static void rdpsnd_oss_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) -{ - BYTE* data; - int offset, size, status, latency; - rdpsndOssPlugin* oss = (rdpsndOssPlugin*)device; - - if (device == NULL || wave == NULL) - return; - - offset = 0; - data = wave->data; - size = wave->length; - latency = oss->latency; - - while (offset < size) - { - status = write(oss->pcm_handle, &data[offset], (size - offset)); + ssize_t status = write(oss->pcm_handle, data, size); if (status < 0) { OSS_LOG_ERR("write fail", errno); rdpsnd_oss_close(device); - rdpsnd_oss_open(device, NULL, latency); + rdpsnd_oss_open(device, NULL, oss->latency); break; } - offset += status; + data += status; + + if (status <= size) + size -= status; + else + size = 0; } - /* From rdpsnd_main.c */ - wave->wTimeStampB = wave->wTimeStampA + wave->wAudioLength + 65 + latency; - wave->wLocalTimeB = wave->wLocalTimeA + wave->wAudioLength + 65 + latency; + return 10; /* TODO: Get real latency in [ms] */ } - static COMMAND_LINE_ARGUMENT_A rdpsnd_oss_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "device" }, @@ -446,7 +402,7 @@ static int rdpsnd_oss_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* a COMMAND_LINE_ARGUMENT_A* arg; rdpsndOssPlugin* oss = (rdpsndOssPlugin*)device; flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, (const char**)args->argv, rdpsnd_oss_args, flags, + status = CommandLineParseArgumentsA(args->argc, args->argv, rdpsnd_oss_args, flags, oss, NULL, NULL); if (status < 0) @@ -514,11 +470,9 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p oss->device.Open = rdpsnd_oss_open; oss->device.FormatSupported = rdpsnd_oss_format_supported; - oss->device.SetFormat = rdpsnd_oss_set_format; oss->device.GetVolume = rdpsnd_oss_get_volume; oss->device.SetVolume = rdpsnd_oss_set_volume; - oss->device.WaveDecode = rdpsnd_oss_wave_decode; - oss->device.WavePlay = rdpsnd_oss_wave_play; + oss->device.Play = rdpsnd_oss_play; oss->device.Close = rdpsnd_oss_close; oss->device.Free = rdpsnd_oss_free; oss->pcm_handle = -1; @@ -526,14 +480,6 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p oss->dev_unit = -1; args = pEntryPoints->args; rdpsnd_oss_parse_addin_args((rdpsndDevicePlugin*)oss, args); - oss->dsp_context = freerdp_dsp_context_new(); - - if (!oss->dsp_context) - { - free(oss); - return CHANNEL_RC_NO_MEMORY; - } - pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)oss); return CHANNEL_RC_OK; } diff --git a/channels/rdpsnd/client/pulse/CMakeLists.txt b/channels/rdpsnd/client/pulse/CMakeLists.txt index 6160ec2..3a57448 100644 --- a/channels/rdpsnd/client/pulse/CMakeLists.txt +++ b/channels/rdpsnd/client/pulse/CMakeLists.txt @@ -25,16 +25,10 @@ include_directories(${PULSE_INCLUDE_DIR}) add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "") - - list(APPEND ${MODULE_PREFIX}_LIBS ${PULSE_LIBRARY}) list(APPEND ${MODULE_PREFIX}_LIBS freerdp) list(APPEND ${MODULE_PREFIX}_LIBS winpr) -if(GSM_FOUND) - list(APPEND ${MODULE_PREFIX}_LIBS ${GSM_LIBRARIES}) -endif() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client/Pulse") diff --git a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c index 2191ec9..b367d95 100644 --- a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c +++ b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c @@ -33,10 +33,6 @@ #include -#ifdef WITH_GSM -#include -#endif - #include #include @@ -53,23 +49,52 @@ struct rdpsnd_pulse_plugin pa_context* context; pa_sample_spec sample_spec; pa_stream* stream; - int format; - int block_size; - int latency; - - FREERDP_DSP_CONTEXT* dsp_context; - -#ifdef WITH_GSM - gsm gsm_context; - wStream* gsmBuffer; -#endif + UINT32 latency; + UINT32 volume; }; +static BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format); + +static void rdpsnd_pulse_get_sink_info(pa_context* c, const pa_sink_info* i, int eol, + void* userdata) +{ + uint8_t x; + UINT16 dwVolumeLeft = ((50 * 0xFFFF) / 100); /* 50% */; + UINT16 dwVolumeRight = ((50 * 0xFFFF) / 100); /* 50% */; + rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) userdata; + + if (!pulse || !c || !i) + return; + + for (x = 0; x < i->volume.channels; x++) + { + pa_volume_t volume = i->volume.values[x]; + + if (volume >= PA_VOLUME_NORM) + volume = PA_VOLUME_NORM - 1; + + switch (x) + { + case 0: + dwVolumeLeft = (UINT16)volume; + break; + + case 1: + dwVolumeRight = (UINT16)volume; + break; + + default: + break; + } + } + + pulse->volume = ((UINT32)dwVolumeLeft << 16U) | dwVolumeRight; +} + static void rdpsnd_pulse_context_state_callback(pa_context* context, void* userdata) { pa_context_state_t state; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) userdata; - state = pa_context_get_state(context); switch (state) @@ -90,6 +115,7 @@ static void rdpsnd_pulse_context_state_callback(pa_context* context, void* userd static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device) { + pa_operation* o; pa_context_state_t state; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; @@ -124,6 +150,11 @@ static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device) pa_threaded_mainloop_wait(pulse->mainloop); } + o = pa_context_get_sink_info_by_index(pulse->context, 0, rdpsnd_pulse_get_sink_info, pulse); + + if (o) + pa_operation_unref(o); + pa_threaded_mainloop_unlock(pulse->mainloop); if (state == PA_CONTEXT_READY) @@ -140,7 +171,6 @@ static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device) static void rdpsnd_pulse_stream_success_callback(pa_stream* stream, int success, void* userdata) { rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) userdata; - pa_threaded_mainloop_signal(pulse->mainloop, 0); } @@ -161,7 +191,6 @@ static void rdpsnd_pulse_stream_state_callback(pa_stream* stream, void* userdata { pa_stream_state_t state; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) userdata; - state = pa_stream_get_state(stream); switch (state) @@ -183,7 +212,6 @@ static void rdpsnd_pulse_stream_state_callback(pa_stream* stream, void* userdata static void rdpsnd_pulse_stream_request_callback(pa_stream* stream, size_t length, void* userdata) { rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) userdata; - pa_threaded_mainloop_signal(pulse->mainloop, 0); } @@ -191,30 +219,27 @@ static void rdpsnd_pulse_close(rdpsndDevicePlugin* device) { rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; -#ifdef WITH_GSM - if (pulse->gsm_context) - gsm_destroy(pulse->gsm_context); -#endif - if (!pulse->context || !pulse->stream) return; pa_threaded_mainloop_lock(pulse->mainloop); - - rdpsnd_pulse_wait_for_operation(pulse, pa_stream_drain(pulse->stream, rdpsnd_pulse_stream_success_callback, pulse)); + rdpsnd_pulse_wait_for_operation(pulse, pa_stream_drain(pulse->stream, + rdpsnd_pulse_stream_success_callback, pulse)); pa_stream_disconnect(pulse->stream); pa_stream_unref(pulse->stream); pulse->stream = NULL; - pa_threaded_mainloop_unlock(pulse->mainloop); } -static void rdpsnd_pulse_set_format_spec(rdpsndPulsePlugin* pulse, AUDIO_FORMAT* format) +static BOOL rdpsnd_pulse_set_format_spec(rdpsndPulsePlugin* pulse, const AUDIO_FORMAT* format) { pa_sample_spec sample_spec = { 0 }; if (!pulse->context) - return; + return FALSE; + + if (!rdpsnd_pulse_format_supported(&pulse->device, format)) + return FALSE; sample_spec.rate = format->nSamplesPerSec; sample_spec.channels = format->nChannels; @@ -227,15 +252,15 @@ static void rdpsnd_pulse_set_format_spec(rdpsndPulsePlugin* pulse, AUDIO_FORMAT* case 8: sample_spec.format = PA_SAMPLE_U8; break; + case 16: sample_spec.format = PA_SAMPLE_S16LE; break; - } - break; - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - sample_spec.format = PA_SAMPLE_S16LE; + default: + return FALSE; + } + break; case WAVE_FORMAT_ALAW: @@ -246,17 +271,16 @@ static void rdpsnd_pulse_set_format_spec(rdpsndPulsePlugin* pulse, AUDIO_FORMAT* sample_spec.format = PA_SAMPLE_ULAW; break; - case WAVE_FORMAT_GSM610: - sample_spec.format = PA_SAMPLE_S16LE; - break; + default: + return FALSE; } pulse->sample_spec = sample_spec; - pulse->format = format->wFormatTag; - pulse->block_size = format->nBlockAlign; + return TRUE; } -static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) +static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, + UINT32 latency) { pa_stream_state_t state; pa_stream_flags_t flags; @@ -267,7 +291,9 @@ static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, if (!pulse->context || pulse->stream) return TRUE; - rdpsnd_pulse_set_format_spec(pulse, format); + if (!rdpsnd_pulse_set_format_spec(pulse, format)) + return FALSE; + pulse->latency = latency; if (pa_sample_spec_valid(&pulse->sample_spec) == 0) @@ -277,8 +303,8 @@ static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, } pa_threaded_mainloop_lock(pulse->mainloop); - pulse->stream = pa_stream_new(pulse->context, "freerdp", &pulse->sample_spec, NULL); + if (!pulse->stream) { pa_threaded_mainloop_unlock(pulse->mainloop); @@ -288,21 +314,20 @@ static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, /* register essential callbacks */ pa_stream_set_state_callback(pulse->stream, rdpsnd_pulse_stream_state_callback, pulse); pa_stream_set_write_callback(pulse->stream, rdpsnd_pulse_stream_request_callback, pulse); - flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE; if (pulse->latency > 0) { buffer_attr.maxlength = pa_usec_to_bytes(pulse->latency * 2 * 1000, &pulse->sample_spec); buffer_attr.tlength = pa_usec_to_bytes(pulse->latency * 1000, &pulse->sample_spec); - buffer_attr.prebuf = (UINT32) -1; - buffer_attr.minreq = (UINT32) -1; - buffer_attr.fragsize = (UINT32) -1; + buffer_attr.prebuf = (UINT32) - 1; + buffer_attr.minreq = (UINT32) - 1; + buffer_attr.fragsize = (UINT32) - 1; flags |= PA_STREAM_ADJUST_LATENCY; } if (pa_stream_connect_playback(pulse->stream, - pulse->device_name, pulse->latency > 0 ? &buffer_attr : NULL, flags, NULL, NULL) < 0) + pulse->device_name, pulse->latency > 0 ? &buffer_attr : NULL, flags, NULL, NULL) < 0) { pa_threaded_mainloop_unlock(pulse->mainloop); return TRUE; @@ -326,17 +351,7 @@ static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, pa_threaded_mainloop_unlock(pulse->mainloop); if (state == PA_STREAM_READY) - { - freerdp_dsp_context_reset_adpcm(pulse->dsp_context); - -#ifdef WITH_GSM - if (pulse->gsm_context) - gsm_destroy(pulse->gsm_context); - - pulse->gsm_context = gsm_create(); -#endif return TRUE; - } rdpsnd_pulse_close(device); return FALSE; @@ -369,83 +384,57 @@ static void rdpsnd_pulse_free(rdpsndDevicePlugin* device) pulse->mainloop = NULL; } -#ifdef WITH_GSM - Stream_Free(pulse->gsmBuffer, TRUE); -#endif - free(pulse->device_name); - freerdp_dsp_context_free(pulse->dsp_context); free(pulse); } -static BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT* format) +BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format) { - rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; - - if (!pulse->context) - return FALSE; - switch (format->wFormatTag) { case WAVE_FORMAT_PCM: if (format->cbSize == 0 && - (format->nSamplesPerSec <= PA_RATE_MAX) && - (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && - (format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX)) + (format->nSamplesPerSec <= PA_RATE_MAX) && + (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && + (format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX)) { return TRUE; } + break; case WAVE_FORMAT_ALAW: case WAVE_FORMAT_MULAW: if (format->cbSize == 0 && - (format->nSamplesPerSec <= PA_RATE_MAX) && - (format->wBitsPerSample == 8) && - (format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX)) + (format->nSamplesPerSec <= PA_RATE_MAX) && + (format->wBitsPerSample == 8) && + (format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX)) { return TRUE; } - break; - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - if ((format->nSamplesPerSec <= PA_RATE_MAX) && - (format->wBitsPerSample == 4) && - (format->nChannels == 1 || format->nChannels == 2)) - { - return TRUE; - } break; - -#ifdef WITH_GSM - case WAVE_FORMAT_GSM610: - if ((format->nSamplesPerSec <= PA_RATE_MAX) && - (format->nBlockAlign == 65) && (format->nChannels == 1)) - { - return TRUE; - } - break; -#endif } return FALSE; } -static BOOL rdpsnd_pulse_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) +static UINT32 rdpsnd_pulse_get_volume(rdpsndDevicePlugin* device) { + pa_operation* o; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; - if (pulse->stream) - { - pa_threaded_mainloop_lock(pulse->mainloop); - pa_stream_disconnect(pulse->stream); - pa_stream_unref(pulse->stream); - pulse->stream = NULL; - pa_threaded_mainloop_unlock(pulse->mainloop); - } + if (!pulse) + return 0; - return rdpsnd_pulse_open(device, format, latency); + if (!pulse->context || !pulse->mainloop) + return 0; + + pa_threaded_mainloop_lock(pulse->mainloop); + o = pa_context_get_sink_info_by_index(pulse->context, 0, rdpsnd_pulse_get_sink_info, pulse); + pa_operation_unref(o); + pa_threaded_mainloop_unlock(pulse->mainloop); + return pulse->volume; } static BOOL rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value) @@ -459,17 +448,15 @@ static BOOL rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value) if (!pulse->context || !pulse->stream) return FALSE; - left = (pa_volume_t) (value & 0xFFFF); - right = (pa_volume_t) ((value >> 16) & 0xFFFF); - + left = (pa_volume_t)(value & 0xFFFF); + right = (pa_volume_t)((value >> 16) & 0xFFFF); pa_cvolume_init(&cv); cv.channels = 2; cv.values[0] = PA_VOLUME_MUTED + (left * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / 0xFFFF; cv.values[1] = PA_VOLUME_MUTED + (right * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / 0xFFFF; - pa_threaded_mainloop_lock(pulse->mainloop); - - operation = pa_context_set_sink_input_volume(pulse->context, pa_stream_get_index(pulse->stream), &cv, NULL, NULL); + operation = pa_context_set_sink_input_volume(pulse->context, pa_stream_get_index(pulse->stream), + &cv, NULL, NULL); if (operation) pa_operation_unref(operation); @@ -478,112 +465,46 @@ static BOOL rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value) return TRUE; } -static BYTE* rdpsnd_pulse_convert_audio(rdpsndDevicePlugin* device, BYTE* data, int* size) +static UINT rdpsnd_pulse_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size) { - BYTE* pcmData = NULL; - rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; - - if (pulse->format == WAVE_FORMAT_ADPCM) - { - pulse->dsp_context->decode_ms_adpcm(pulse->dsp_context, - data, *size, pulse->sample_spec.channels, pulse->block_size); - - *size = pulse->dsp_context->adpcm_size; - pcmData = pulse->dsp_context->adpcm_buffer; - } - else if (pulse->format == WAVE_FORMAT_DVI_ADPCM) - { - pulse->dsp_context->decode_ima_adpcm(pulse->dsp_context, - data, *size, pulse->sample_spec.channels, pulse->block_size); - - *size = pulse->dsp_context->adpcm_size; - pcmData = pulse->dsp_context->adpcm_buffer; - } -#ifdef WITH_GSM - else if (pulse->format == WAVE_FORMAT_GSM610) - { - int inPos = 0; - int inSize = *size; - UINT16 gsmBlockBuffer[160]; - - Stream_SetPosition(pulse->gsmBuffer, 0); - - while (inSize) - { - ZeroMemory(gsmBlockBuffer, sizeof(gsmBlockBuffer)); - gsm_decode(pulse->gsm_context, (gsm_byte*) &data[inPos], (gsm_signal*) gsmBlockBuffer); - - if ((inPos % 65) == 0) - { - inPos += 33; - inSize -= 33; - } - else - { - inPos += 32; - inSize -= 32; - } - - if (!Stream_EnsureRemainingCapacity(pulse->gsmBuffer, 160 * 2)) - return NULL; - Stream_Write(pulse->gsmBuffer, (void*) gsmBlockBuffer, 160 * 2); - } - - Stream_SealLength(pulse->gsmBuffer); - - pcmData = Stream_Buffer(pulse->gsmBuffer); - *size = Stream_Length(pulse->gsmBuffer); - } -#endif - else - { - pcmData = data; - } - - return pcmData; -} - -static void rdpsnd_pulse_play(rdpsndDevicePlugin* device, BYTE* data, int size) -{ - int length; + size_t length; int status; - BYTE* pcmData; + pa_usec_t latency; + int negative; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; - if (!pulse->stream) - return; - - pcmData = rdpsnd_pulse_convert_audio(device, data, &size); - if (!pcmData) - return; + if (!pulse->stream || !data) + return 0; pa_threaded_mainloop_lock(pulse->mainloop); while (size > 0) { while ((length = pa_stream_writable_size(pulse->stream)) == 0) - { pa_threaded_mainloop_wait(pulse->mainloop); - } - if (length < 0) + if (length == (size_t) -1) break; if (length > size) length = size; - status = pa_stream_write(pulse->stream, pcmData, length, NULL, 0LL, PA_SEEK_RELATIVE); + status = pa_stream_write(pulse->stream, data, length, NULL, 0LL, PA_SEEK_RELATIVE); if (status < 0) { break; } - pcmData += length; + data += length; size -= length; } + if (pa_stream_get_latency(pulse->stream, &latency, &negative) != 0) + latency = 0; + pa_threaded_mainloop_unlock(pulse->mainloop); + return latency / 1000; } static void rdpsnd_pulse_start(rdpsndDevicePlugin* device) @@ -598,7 +519,7 @@ static void rdpsnd_pulse_start(rdpsndDevicePlugin* device) pa_threaded_mainloop_unlock(pulse->mainloop); } -COMMAND_LINE_ARGUMENT_A rdpsnd_pulse_args[] = +static COMMAND_LINE_ARGUMENT_A rdpsnd_pulse_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "device" }, { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } @@ -615,29 +536,28 @@ static UINT rdpsnd_pulse_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = CommandLineParseArgumentsA(args->argc, args->argv, + rdpsnd_pulse_args, flags, pulse, NULL, NULL); - status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, - rdpsnd_pulse_args, flags, pulse, NULL, NULL); if (status < 0) return ERROR_INVALID_DATA; arg = rdpsnd_pulse_args; + do { if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) continue; CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dev") { pulse->device_name = _strdup(arg->Value); + if (!pulse->device_name) return ERROR_OUTOFMEMORY; } - CommandLineSwitchEnd(arg) } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); @@ -661,24 +581,25 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p ADDIN_ARGV* args; rdpsndPulsePlugin* pulse; UINT ret; - pulse = (rdpsndPulsePlugin*) calloc(1, sizeof(rdpsndPulsePlugin)); + if (!pulse) return CHANNEL_RC_NO_MEMORY; pulse->device.Open = rdpsnd_pulse_open; pulse->device.FormatSupported = rdpsnd_pulse_format_supported; - pulse->device.SetFormat = rdpsnd_pulse_set_format; + pulse->device.GetVolume = rdpsnd_pulse_get_volume; pulse->device.SetVolume = rdpsnd_pulse_set_volume; pulse->device.Play = rdpsnd_pulse_play; pulse->device.Start = rdpsnd_pulse_start; pulse->device.Close = rdpsnd_pulse_close; pulse->device.Free = rdpsnd_pulse_free; - args = pEntryPoints->args; + if (args->argc > 1) { - ret = rdpsnd_pulse_parse_addin_args((rdpsndDevicePlugin *) pulse, args); + ret = rdpsnd_pulse_parse_addin_args((rdpsndDevicePlugin*) pulse, args); + if (ret != CHANNEL_RC_OK) { WLog_ERR(TAG, "error parsing arguments"); @@ -687,17 +608,6 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p } ret = CHANNEL_RC_NO_MEMORY; - pulse->dsp_context = freerdp_dsp_context_new(); - if (!pulse->dsp_context) - goto error; - -#ifdef WITH_GSM - pulse->gsmBuffer = Stream_New(NULL, 4096); - if (!pulse->gsmBuffer) - goto error; -#endif - - pulse->mainloop = pa_threaded_mainloop_new(); if (!pulse->mainloop) @@ -709,14 +619,13 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p goto error; pa_context_set_state_callback(pulse->context, rdpsnd_pulse_context_state_callback, pulse); - ret = ERROR_INVALID_OPERATION; + if (!rdpsnd_pulse_connect((rdpsndDevicePlugin*)pulse)) goto error; pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) pulse); return CHANNEL_RC_OK; - error: rdpsnd_pulse_free((rdpsndDevicePlugin*)pulse); return ret; diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index 4c327f7..cc4167c 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -45,29 +45,29 @@ #include #include +#include +#include "rdpsnd_common.h" #include "rdpsnd_main.h" -#define TIME_DELAY_MS 65 - struct rdpsnd_plugin { CHANNEL_DEF channelDef; CHANNEL_ENTRY_POINTS_FREERDP_EX channelEntryPoints; HANDLE thread; + wStreamPool* pool; wStream* data_in; + void* InitHandle; DWORD OpenHandle; - wMessagePipe* MsgPipe; wLog* log; HANDLE stopEvent; - HANDLE ScheduleThread; BYTE cBlockNo; UINT16 wQualityMode; - int wCurrentFormatNo; + UINT16 wCurrentFormatNo; AUDIO_FORMAT* ServerFormats; UINT16 NumberOfServerFormats; @@ -76,17 +76,17 @@ struct rdpsnd_plugin UINT16 NumberOfClientFormats; BOOL attached; + BOOL connected; BOOL expectingWave; BYTE waveData[4]; UINT16 waveDataSize; UINT32 wTimeStamp; + UINT32 wArrivalTime; - int latency; + UINT32 latency; BOOL isOpen; - UINT16 fixedFormat; - UINT16 fixedChannel; - UINT32 fixedRate; + AUDIO_FORMAT* fixed_format; char* subsystem; char* device_name; @@ -94,98 +94,20 @@ struct rdpsnd_plugin /* Device plugin */ rdpsndDevicePlugin* device; rdpContext* rdpcontext; + + wQueue* queue; + FREERDP_DSP_CONTEXT* dsp_context; }; +static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd); +static void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd); + /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_confirm_wave(rdpsndPlugin* rdpsnd, RDPSND_WAVE* wave); - -static DWORD WINAPI rdpsnd_schedule_thread(LPVOID arg) -{ - wMessage message; - UINT16 wTimeDiff; - UINT16 wTimeStamp; - UINT16 wCurrentTime; - RDPSND_WAVE* wave; - rdpsndPlugin* rdpsnd = (rdpsndPlugin*) arg; - HANDLE events[2]; - UINT error = CHANNEL_RC_OK; - DWORD status; - events[0] = MessageQueue_Event(rdpsnd->MsgPipe->Out); - events[1] = rdpsnd->stopEvent; - - while (1) - { - status = WaitForMultipleObjects(2, events, FALSE, INFINITE); - - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"!", error); - break; - } - - status = WaitForSingleObject(rdpsnd->stopEvent, 0); - - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); - break; - } - - if (status == WAIT_OBJECT_0) - break; - - status = WaitForSingleObject(events[0], 0); - - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); - break; - } - - if (!MessageQueue_Peek(rdpsnd->MsgPipe->Out, &message, TRUE)) - { - WLog_ERR(TAG, "MessageQueue_Peek failed!"); - error = ERROR_INTERNAL_ERROR; - break; - } - - if (message.id == WMQ_QUIT) - break; - - wave = (RDPSND_WAVE*) message.wParam; - wCurrentTime = (UINT16) GetTickCount(); - wTimeStamp = wave->wLocalTimeB; - - if (wCurrentTime <= wTimeStamp) - { - wTimeDiff = wTimeStamp - wCurrentTime; - Sleep(wTimeDiff); - } - - if ((error = rdpsnd_confirm_wave(rdpsnd, wave))) - { - WLog_ERR(TAG, "error confirming wave"); - break; - } - - message.wParam = NULL; - free(wave); - } - - if (error && rdpsnd->rdpcontext) - setChannelError(rdpsnd->rdpcontext, error, - "rdpsnd_schedule_thread reported an error"); - - ExitThread(error); - return error; -} +static UINT rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s); /** * Function description @@ -214,65 +136,33 @@ static UINT rdpsnd_send_quality_mode_pdu(rdpsndPlugin* rdpsnd) static void rdpsnd_select_supported_audio_formats(rdpsndPlugin* rdpsnd) { - int index; - AUDIO_FORMAT* serverFormat; - AUDIO_FORMAT* clientFormat; - rdpsnd_free_audio_formats(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats); + UINT16 index; + audio_formats_free(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats); rdpsnd->NumberOfClientFormats = 0; rdpsnd->ClientFormats = NULL; if (!rdpsnd->NumberOfServerFormats) return; - rdpsnd->ClientFormats = (AUDIO_FORMAT*) calloc( - rdpsnd->NumberOfServerFormats, - sizeof(AUDIO_FORMAT)); + rdpsnd->ClientFormats = audio_formats_new(rdpsnd->NumberOfServerFormats); if (!rdpsnd->ClientFormats) return; - for (index = 0; index < (int) rdpsnd->NumberOfServerFormats; index++) + for (index = 0; index < rdpsnd->NumberOfServerFormats; index++) { - serverFormat = &rdpsnd->ServerFormats[index]; + const AUDIO_FORMAT* serverFormat = &rdpsnd->ServerFormats[index]; - if (rdpsnd->fixedFormat > 0 - && (rdpsnd->fixedFormat != serverFormat->wFormatTag)) + if (!audio_format_compatible(rdpsnd->fixed_format, serverFormat)) continue; - if (rdpsnd->fixedChannel > 0 - && (rdpsnd->fixedChannel != serverFormat->nChannels)) - continue; - - if (rdpsnd->fixedRate > 0 - && (rdpsnd->fixedRate != serverFormat->nSamplesPerSec)) - continue; - - if (rdpsnd->device - && rdpsnd->device->FormatSupported(rdpsnd->device, serverFormat)) + if (freerdp_dsp_supports_format(serverFormat, FALSE) || + rdpsnd->device->FormatSupported(rdpsnd->device, serverFormat)) { - clientFormat = &rdpsnd->ClientFormats[rdpsnd->NumberOfClientFormats++]; - CopyMemory(clientFormat, serverFormat, sizeof(AUDIO_FORMAT)); - clientFormat->cbSize = 0; - - if (serverFormat->cbSize > 0) - { - clientFormat->data = (BYTE*) malloc(serverFormat->cbSize); - CopyMemory(clientFormat->data, serverFormat->data, serverFormat->cbSize); - clientFormat->cbSize = serverFormat->cbSize; - } + AUDIO_FORMAT* clientFormat = &rdpsnd->ClientFormats[rdpsnd->NumberOfClientFormats++]; + audio_format_copy(serverFormat, clientFormat); } } - -#if 0 - WLog_ERR(TAG, "Server "); - rdpsnd_print_audio_formats(rdpsnd->ServerFormats, - rdpsnd->NumberOfServerFormats); - WLog_ERR(TAG, ""); - WLog_ERR(TAG, "Client "); - rdpsnd_print_audio_formats(rdpsnd->ClientFormats, - rdpsnd->NumberOfClientFormats); - WLog_ERR(TAG, ""); -#endif } /** @@ -282,28 +172,16 @@ static void rdpsnd_select_supported_audio_formats(rdpsndPlugin* rdpsnd) */ static UINT rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd) { - int index; + UINT16 index; wStream* pdu; UINT16 length; UINT32 dwVolume; - UINT16 dwVolumeLeft; - UINT16 dwVolumeRight; UINT16 wNumberOfFormats; - AUDIO_FORMAT* clientFormat; - dwVolumeLeft = ((50 * 0xFFFF) / 100); /* 50% */ - dwVolumeRight = ((50 * 0xFFFF) / 100); /* 50% */ - dwVolume = (dwVolumeLeft << 16) | dwVolumeRight; - - if (rdpsnd->device) - { - if (rdpsnd->device->GetVolume) - dwVolume = rdpsnd->device->GetVolume(rdpsnd->device); - } - + dwVolume = IFCALLRESULT(0, rdpsnd->device->GetVolume, rdpsnd->device); wNumberOfFormats = rdpsnd->NumberOfClientFormats; length = 4 + 20; - for (index = 0; index < (int) wNumberOfFormats; index++) + for (index = 0; index < wNumberOfFormats; index++) length += (18 + rdpsnd->ClientFormats[index].cbSize); pdu = Stream_New(NULL, length); @@ -323,22 +201,18 @@ static UINT rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd) Stream_Write_UINT16(pdu, 0); /* wDGramPort */ Stream_Write_UINT16(pdu, wNumberOfFormats); /* wNumberOfFormats */ Stream_Write_UINT8(pdu, 0); /* cLastBlockConfirmed */ - Stream_Write_UINT16(pdu, 6); /* wVersion */ + Stream_Write_UINT16(pdu, CHANNEL_VERSION_WIN_MAX); /* wVersion */ Stream_Write_UINT8(pdu, 0); /* bPad */ - for (index = 0; index < (int) wNumberOfFormats; index++) + for (index = 0; index < wNumberOfFormats; index++) { - clientFormat = &rdpsnd->ClientFormats[index]; - Stream_Write_UINT16(pdu, clientFormat->wFormatTag); - Stream_Write_UINT16(pdu, clientFormat->nChannels); - Stream_Write_UINT32(pdu, clientFormat->nSamplesPerSec); - Stream_Write_UINT32(pdu, clientFormat->nAvgBytesPerSec); - Stream_Write_UINT16(pdu, clientFormat->nBlockAlign); - Stream_Write_UINT16(pdu, clientFormat->wBitsPerSample); - Stream_Write_UINT16(pdu, clientFormat->cbSize); + const AUDIO_FORMAT* clientFormat = &rdpsnd->ClientFormats[index]; - if (clientFormat->cbSize > 0) - Stream_Write(pdu, clientFormat->data, clientFormat->cbSize); + if (!audio_format_write(pdu, clientFormat)) + { + Stream_Free(pdu, TRUE); + return ERROR_INTERNAL_ERROR; + } } WLog_Print(rdpsnd->log, WLOG_DEBUG, "Client Audio Formats"); @@ -353,12 +227,11 @@ static UINT rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd) static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream* s) { - int index; + UINT16 index; UINT16 wVersion; - AUDIO_FORMAT* format; UINT16 wNumberOfFormats; UINT ret = ERROR_BAD_LENGTH; - rdpsnd_free_audio_formats(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats); + audio_formats_free(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats); rdpsnd->NumberOfServerFormats = 0; rdpsnd->ServerFormats = NULL; @@ -379,42 +252,17 @@ static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, if (Stream_GetRemainingLength(s) / 14 < wNumberOfFormats) return ERROR_BAD_LENGTH; - rdpsnd->ServerFormats = (AUDIO_FORMAT*) calloc(wNumberOfFormats, - sizeof(AUDIO_FORMAT)); + rdpsnd->ServerFormats = audio_formats_new(wNumberOfFormats); if (!rdpsnd->ServerFormats) return CHANNEL_RC_NO_MEMORY; - for (index = 0; index < (int) wNumberOfFormats; index++) + for (index = 0; index < wNumberOfFormats; index++) { - format = &rdpsnd->ServerFormats[index]; + AUDIO_FORMAT* format = &rdpsnd->ServerFormats[index]; - if (Stream_GetRemainingLength(s) < 14) + if (!audio_format_read(s, format)) goto out_fail; - - Stream_Read_UINT16(s, format->wFormatTag); /* wFormatTag */ - Stream_Read_UINT16(s, format->nChannels); /* nChannels */ - Stream_Read_UINT32(s, format->nSamplesPerSec); /* nSamplesPerSec */ - Stream_Read_UINT32(s, format->nAvgBytesPerSec); /* nAvgBytesPerSec */ - Stream_Read_UINT16(s, format->nBlockAlign); /* nBlockAlign */ - Stream_Read_UINT16(s, format->wBitsPerSample); /* wBitsPerSample */ - Stream_Read_UINT16(s, format->cbSize); /* cbSize */ - - if (format->cbSize > 0) - { - if (Stream_GetRemainingLength(s) < format->cbSize) - goto out_fail; - - format->data = (BYTE*) malloc(format->cbSize); - - if (!format->data) - { - ret = CHANNEL_RC_NO_MEMORY; - goto out_fail; - } - - Stream_Read(s, format->data, format->cbSize); - } } rdpsnd_select_supported_audio_formats(rdpsnd); @@ -423,18 +271,15 @@ static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, if (ret == CHANNEL_RC_OK) { - if (wVersion >= 6) + if (wVersion >= CHANNEL_VERSION_WIN_7) ret = rdpsnd_send_quality_mode_pdu(rdpsnd); } return ret; out_fail: - - for (index = 0; index < (int) wNumberOfFormats; index++) - free(format->data); - - free(rdpsnd->ServerFormats); + audio_formats_free(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats); rdpsnd->ServerFormats = NULL; + rdpsnd->NumberOfServerFormats = 0; return ret; } @@ -487,6 +332,48 @@ static UINT rdpsnd_recv_training_pdu(rdpsndPlugin* rdpsnd, wStream* s) return rdpsnd_send_training_confirm_pdu(rdpsnd, wTimeStamp, wPackSize); } +static BOOL rdpsnd_ensure_device_is_open(rdpsndPlugin* rdpsnd, UINT32 wFormatNo, + const AUDIO_FORMAT* format) +{ + if (!rdpsnd) + return FALSE; + + if (!rdpsnd->isOpen || (wFormatNo != rdpsnd->wCurrentFormatNo)) + { + BOOL rc; + BOOL supported; + AUDIO_FORMAT deviceFormat = *format; + rdpsnd_recv_close_pdu(rdpsnd); + supported = IFCALLRESULT(FALSE, rdpsnd->device->FormatSupported, rdpsnd->device, format); + + if (!supported) + { + deviceFormat.wFormatTag = WAVE_FORMAT_PCM; + deviceFormat.wBitsPerSample = 16; + deviceFormat.cbSize = 0; + } + + WLog_Print(rdpsnd->log, WLOG_DEBUG, "Opening device with format %s [backend %s]", + audio_format_get_tag_string(format->wFormatTag), + audio_format_get_tag_string(deviceFormat.wFormatTag)); + rc = IFCALLRESULT(FALSE, rdpsnd->device->Open, rdpsnd->device, &deviceFormat, rdpsnd->latency); + + if (!rc) + return FALSE; + + if (!supported) + { + if (!freerdp_dsp_context_reset(rdpsnd->dsp_context, format)) + return FALSE; + } + + rdpsnd->isOpen = TRUE; + rdpsnd->wCurrentFormatNo = wFormatNo; + } + + return TRUE; +} + /** * Function description * @@ -496,47 +383,30 @@ static UINT rdpsnd_recv_wave_info_pdu(rdpsndPlugin* rdpsnd, wStream* s, UINT16 BodySize) { UINT16 wFormatNo; - AUDIO_FORMAT* format; - rdpsnd->expectingWave = TRUE; + const AUDIO_FORMAT* format; if (Stream_GetRemainingLength(s) < 12) return ERROR_BAD_LENGTH; + rdpsnd->wArrivalTime = GetTickCount(); Stream_Read_UINT16(s, rdpsnd->wTimeStamp); Stream_Read_UINT16(s, wFormatNo); + + if (wFormatNo >= rdpsnd->NumberOfClientFormats) + return ERROR_INVALID_DATA; + Stream_Read_UINT8(s, rdpsnd->cBlockNo); Stream_Seek(s, 3); /* bPad */ Stream_Read(s, rdpsnd->waveData, 4); rdpsnd->waveDataSize = BodySize - 8; format = &rdpsnd->ClientFormats[wFormatNo]; - WLog_Print(rdpsnd->log, WLOG_DEBUG, "WaveInfo: cBlockNo: %"PRIu8" wFormatNo: %"PRIu16"", - rdpsnd->cBlockNo, wFormatNo); + WLog_Print(rdpsnd->log, WLOG_DEBUG, "WaveInfo: cBlockNo: %"PRIu8" wFormatNo: %"PRIu16" [%s]", + rdpsnd->cBlockNo, wFormatNo, audio_format_get_tag_string(format->wFormatTag)); - if (!rdpsnd->isOpen) - { - rdpsnd->isOpen = TRUE; - rdpsnd->wCurrentFormatNo = wFormatNo; - - //rdpsnd_print_audio_format(format); - - if (rdpsnd->device && rdpsnd->device->Open && - !rdpsnd->device->Open(rdpsnd->device, format, rdpsnd->latency)) - { - return CHANNEL_RC_INITIALIZATION_ERROR; - } - } - else if (wFormatNo != rdpsnd->wCurrentFormatNo) - { - rdpsnd->wCurrentFormatNo = wFormatNo; - - if (rdpsnd->device) - { - if (rdpsnd->device->SetFormat - && !rdpsnd->device->SetFormat(rdpsnd->device, format, rdpsnd->latency)) - return CHANNEL_RC_INITIALIZATION_ERROR; - } - } + if (!rdpsnd_ensure_device_is_open(rdpsnd, wFormatNo, format)) + return ERROR_INTERNAL_ERROR; + rdpsnd->expectingWave = TRUE; return CHANNEL_RC_OK; } @@ -566,40 +436,50 @@ static UINT rdpsnd_send_wave_confirm_pdu(rdpsndPlugin* rdpsnd, return rdpsnd_virtual_channel_write(rdpsnd, pdu); } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rdpsnd_confirm_wave(rdpsndPlugin* rdpsnd, RDPSND_WAVE* wave) +static UINT rdpsnd_treat_wave(rdpsndPlugin* rdpsnd, wStream* s, size_t size) { - WLog_Print(rdpsnd->log, WLOG_DEBUG, - "WaveConfirm: cBlockNo: %"PRIu8" wTimeStamp: %"PRIu16" wTimeDiff: %d", - wave->cBlockNo, wave->wTimeStampB, wave->wTimeStampB - wave->wTimeStampA); - return rdpsnd_send_wave_confirm_pdu(rdpsnd, wave->wTimeStampB, wave->cBlockNo); -} + BYTE* data; + AUDIO_FORMAT* format; + DWORD end; + DWORD diffMS; + UINT latency = 0; -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rdpsnd_device_send_wave_confirm_pdu(rdpsndDevicePlugin* device, - RDPSND_WAVE* wave) -{ - if (device->DisableConfirmThread) - return rdpsnd_confirm_wave(device->rdpsnd, wave); + if (Stream_GetRemainingLength(s) < size) + return ERROR_BAD_LENGTH; - if (!MessageQueue_Post(device->rdpsnd->MsgPipe->Out, NULL, 0, (void*) wave, - NULL)) + 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); + + if (rdpsnd->device && rdpsnd->attached) { - WLog_ERR(TAG, "MessageQueue_Post failed!"); - return ERROR_INTERNAL_ERROR; + UINT status = CHANNEL_RC_OK; + wStream* pcmData = StreamPool_Take(rdpsnd->pool, 4096); + + if (rdpsnd->device->FormatSupported(rdpsnd->device, format)) + latency = IFCALLRESULT(0, rdpsnd->device->Play, rdpsnd->device, data, size); + else if (freerdp_dsp_decode(rdpsnd->dsp_context, format, data, size, pcmData)) + { + Stream_SealLength(pcmData); + latency = IFCALLRESULT(0, rdpsnd->device->Play, rdpsnd->device, Stream_Buffer(pcmData), + Stream_Length(pcmData)); + } + else + status = ERROR_INTERNAL_ERROR; + + StreamPool_Return(rdpsnd->pool, pcmData); + + if (status != CHANNEL_RC_OK) + return status; } - return CHANNEL_RC_OK; + end = GetTickCount(); + diffMS = end - rdpsnd->wArrivalTime + latency; + return rdpsnd_send_wave_confirm_pdu(rdpsnd, rdpsnd->wTimeStamp + diffMS, rdpsnd->cBlockNo); } + /** * Function description * @@ -607,90 +487,57 @@ static UINT rdpsnd_device_send_wave_confirm_pdu(rdpsndDevicePlugin* device, */ static UINT rdpsnd_recv_wave_pdu(rdpsndPlugin* rdpsnd, wStream* s) { - int size; - BYTE* data; - RDPSND_WAVE* wave; - AUDIO_FORMAT* format; - UINT status; rdpsnd->expectingWave = FALSE; + /** * The Wave PDU is a special case: it is always sent after a Wave Info PDU, * and we do not process its header. Instead, the header is pad that needs * to be filled with the first four bytes of the audio sample data sent as * part of the preceding Wave Info PDU. */ + if (Stream_GetRemainingLength(s) < 4) + return ERROR_INVALID_DATA; + CopyMemory(Stream_Buffer(s), rdpsnd->waveData, 4); - data = Stream_Buffer(s); - size = (int) Stream_Capacity(s); - wave = (RDPSND_WAVE*) calloc(1, sizeof(RDPSND_WAVE)); + return rdpsnd_treat_wave(rdpsnd, s, rdpsnd->waveDataSize); +} - if (!wave) - { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; - } +static UINT rdpsnd_recv_wave2_pdu(rdpsndPlugin* rdpsnd, wStream* s, UINT16 BodySize) +{ + UINT16 wFormatNo; + AUDIO_FORMAT* format; + UINT32 dwAudioTimeStamp; - wave->wLocalTimeA = GetTickCount(); - wave->wTimeStampA = rdpsnd->wTimeStamp; - wave->wFormatNo = rdpsnd->wCurrentFormatNo; - wave->cBlockNo = rdpsnd->cBlockNo; - wave->data = data; - wave->length = size; - wave->AutoConfirm = TRUE; - format = &rdpsnd->ClientFormats[rdpsnd->wCurrentFormatNo]; - wave->wAudioLength = rdpsnd_compute_audio_time_length(format, size); - WLog_Print(rdpsnd->log, WLOG_DEBUG, "Wave: cBlockNo: %"PRIu8" wTimeStamp: %"PRIu16"", - wave->cBlockNo, wave->wTimeStampA); + if (Stream_GetRemainingLength(s) < 12) + return ERROR_BAD_LENGTH; - if (!rdpsnd->device) - { - wave->wLocalTimeB = wave->wLocalTimeA; - wave->wTimeStampB = wave->wTimeStampA; - status = rdpsnd_confirm_wave(rdpsnd, wave); - free(wave); - return status; - } + Stream_Read_UINT16(s, rdpsnd->wTimeStamp); + Stream_Read_UINT16(s, wFormatNo); + Stream_Read_UINT8(s, rdpsnd->cBlockNo); + Stream_Seek(s, 3); /* bPad */ + Stream_Read_UINT32(s, dwAudioTimeStamp); + rdpsnd->waveDataSize = BodySize - 12; + format = &rdpsnd->ClientFormats[wFormatNo]; + rdpsnd->wArrivalTime = GetTickCount(); + WLog_Print(rdpsnd->log, WLOG_DEBUG, "Wave2PDU: cBlockNo: %"PRIu8" wFormatNo: %"PRIu16", align=%hu", + rdpsnd->cBlockNo, wFormatNo, format->nBlockAlign); - if (rdpsnd->device->WaveDecode - && !rdpsnd->device->WaveDecode(rdpsnd->device, wave)) - { - free(wave); - return CHANNEL_RC_NO_MEMORY; - } + if (!rdpsnd_ensure_device_is_open(rdpsnd, wFormatNo, format)) + return ERROR_INTERNAL_ERROR; - if (rdpsnd->device->WavePlay) - { - IFCALL(rdpsnd->device->WavePlay, rdpsnd->device, wave); - } - else - { - IFCALL(rdpsnd->device->Play, rdpsnd->device, data, size); - } - - if (!rdpsnd->device->WavePlay) - { - wave->wTimeStampB = rdpsnd->wTimeStamp + wave->wAudioLength + TIME_DELAY_MS; - wave->wLocalTimeB = wave->wLocalTimeA + wave->wAudioLength + TIME_DELAY_MS; - } - - status = CHANNEL_RC_OK; - - if (wave->AutoConfirm) - status = rdpsnd->device->WaveConfirm(rdpsnd->device, wave); - - return status; + return rdpsnd_treat_wave(rdpsnd, s, rdpsnd->waveDataSize); } static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd) { - WLog_Print(rdpsnd->log, WLOG_DEBUG, "Close"); - - if (rdpsnd->device) + if (rdpsnd->isOpen) { + WLog_Print(rdpsnd->log, WLOG_DEBUG, "Closing device"); IFCALL(rdpsnd->device->Close, rdpsnd->device); + rdpsnd->isOpen = FALSE; } - - rdpsnd->isOpen = FALSE; + else + WLog_Print(rdpsnd->log, WLOG_DEBUG, "Device already closed"); } /** @@ -700,6 +547,7 @@ static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd) */ static UINT rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s) { + BOOL rc; UINT32 dwVolume; if (Stream_GetRemainingLength(s) < 4) @@ -707,9 +555,9 @@ static UINT rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s) Stream_Read_UINT32(s, dwVolume); WLog_Print(rdpsnd->log, WLOG_DEBUG, "Volume: 0x%08"PRIX32"", dwVolume); + rc = IFCALLRESULT(FALSE, rdpsnd->device->SetVolume, rdpsnd->device, dwVolume); - if (rdpsnd->device && rdpsnd->device->SetVolume && - !rdpsnd->device->SetVolume(rdpsnd->device, dwVolume)) + if (!rc) { WLog_ERR(TAG, "error setting volume"); return CHANNEL_RC_INITIALIZATION_ERROR; @@ -745,11 +593,6 @@ static UINT rdpsnd_recv_pdu(rdpsndPlugin* rdpsnd, wStream* s) Stream_Seek_UINT8(s); /* bPad */ Stream_Read_UINT16(s, BodySize); - if (!rdpsnd->attached) - goto out; - - //WLog_ERR(TAG, "msgType %"PRIu8" BodySize %"PRIu16"", msgType, BodySize); - switch (msgType) { case SNDC_FORMATS: @@ -772,13 +615,17 @@ static UINT rdpsnd_recv_pdu(rdpsndPlugin* rdpsnd, wStream* s) status = rdpsnd_recv_volume_pdu(rdpsnd, s); break; + case SNDC_WAVE2: + status = rdpsnd_recv_wave2_pdu(rdpsnd, s, BodySize); + break; + default: WLog_ERR(TAG, "unknown msgType %"PRIu8"", msgType); break; } out: - Stream_Free(s, TRUE); + StreamPool_Return(rdpsnd->pool, s); return status; } @@ -793,7 +640,6 @@ static void rdpsnd_register_device_plugin(rdpsndPlugin* rdpsnd, rdpsnd->device = device; device->rdpsnd = rdpsnd; - device->WaveConfirm = rdpsnd_device_send_wave_confirm_pdu; } /** @@ -865,7 +711,7 @@ static UINT rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args) if (args->argc > 1) { flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON; - status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, + status = CommandLineParseArgumentsA(args->argc, args->argv, rdpsnd_args, flags, rdpsnd, NULL, NULL); if (status < 0) @@ -897,7 +743,7 @@ static UINT rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args) if ((errno != 0) || (val > UINT16_MAX)) return CHANNEL_RC_INITIALIZATION_ERROR; - rdpsnd->fixedFormat = val; + rdpsnd->fixed_format->wFormatTag = val; } CommandLineSwitchCase(arg, "rate") { @@ -906,7 +752,7 @@ static UINT rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args) if ((errno != 0) || (val > UINT32_MAX)) return CHANNEL_RC_INITIALIZATION_ERROR; - rdpsnd->fixedRate = val; + rdpsnd->fixed_format->nSamplesPerSec = val; } CommandLineSwitchCase(arg, "channel") { @@ -915,7 +761,7 @@ static UINT rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args) if ((errno != 0) || (val > UINT16_MAX)) return CHANNEL_RC_INITIALIZATION_ERROR; - rdpsnd->fixedChannel = val; + rdpsnd->fixed_format->nChannels = val; } CommandLineSwitchCase(arg, "latency") { @@ -967,10 +813,39 @@ static UINT rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args) */ static UINT rdpsnd_process_connect(rdpsndPlugin* rdpsnd) { + const struct + { + const char* subsystem; + const char* device; + } + backends[] = + { +#if defined(WITH_IOSAUDIO) + {"ios", ""}, +#endif +#if defined(WITH_OPENSLES) + {"opensles", ""}, +#endif +#if defined(WITH_PULSE) + {"pulse", ""}, +#endif +#if defined(WITH_ALSA) + {"alsa", "default"}, +#endif +#if defined(WITH_OSS) + {"oss", ""}, +#endif +#if defined(WITH_MACAUDIO) + {"mac", "default"}, +#endif +#if defined(WITH_WINMM) + { "winmm", ""}, +#endif + { "fake", "" } + }; ADDIN_ARGV* args; UINT status = ERROR_INTERNAL_ERROR; - char* subsystem_name = NULL, *device_name = NULL; - rdpsnd->latency = -1; + rdpsnd->latency = 0; args = (ADDIN_ARGV*) rdpsnd->channelEntryPoints.pExtendedData; if (args) @@ -983,9 +858,6 @@ static UINT rdpsnd_process_connect(rdpsndPlugin* rdpsnd) if (rdpsnd->subsystem) { - if (strcmp(rdpsnd->subsystem, "fake") == 0) - return CHANNEL_RC_OK; - if ((status = rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args))) { WLog_ERR(TAG, "unable to load the %s subsystem plugin because of error %"PRIu32"", @@ -995,134 +867,29 @@ static UINT rdpsnd_process_connect(rdpsndPlugin* rdpsnd) } else { -#if defined(WITH_IOSAUDIO) + size_t x; - if (!rdpsnd->device) + for (x = 0; x < ARRAYSIZE(backends); x++) { - subsystem_name = "ios"; - device_name = ""; + const char* subsystem_name = backends[x].subsystem; + const char* device_name = backends[x].device; if ((status = rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args))) WLog_ERR(TAG, "unable to load the %s subsystem plugin because of error %"PRIu32"", subsystem_name, status); - } -#endif -#if defined(WITH_OPENSLES) + if (!rdpsnd->device) + continue; - if (!rdpsnd->device) - { - subsystem_name = "opensles"; - device_name = ""; - - if ((status = rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args))) - WLog_ERR(TAG, "unable to load the %s subsystem plugin because of error %"PRIu32"", - subsystem_name, status); - } - -#endif -#if defined(WITH_PULSE) - - if (!rdpsnd->device) - { - subsystem_name = "pulse"; - device_name = ""; - - if ((status = rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args))) - WLog_ERR(TAG, "unable to load the %s subsystem plugin because of error %"PRIu32"", - subsystem_name, status); - } - -#endif -#if defined(WITH_ALSA) - - if (!rdpsnd->device) - { - subsystem_name = "alsa"; - device_name = "default"; - - if ((status = rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args))) - WLog_ERR(TAG, "unable to load the %s subsystem plugin because of error %"PRIu32"", - subsystem_name, status); - } - -#endif -#if defined(WITH_OSS) - - if (!rdpsnd->device) - { - subsystem_name = "oss"; - device_name = ""; - - if ((status = rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args))) - WLog_ERR(TAG, "unable to load the %s subsystem plugin because of error %"PRIu32"", - subsystem_name, status); - } - -#endif -#if defined(WITH_MACAUDIO) - - if (!rdpsnd->device) - { - subsystem_name = "mac"; - device_name = "default"; - - if ((status = rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args))) - WLog_ERR(TAG, "unable to load the %s subsystem plugin because of error %"PRIu32"", - subsystem_name, status); - } - -#endif -#if defined(WITH_WINMM) - - if (!rdpsnd->device) - { - subsystem_name = "winmm"; - device_name = ""; - - if ((status = rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args))) - WLog_ERR(TAG, "unable to load the %s subsystem plugin because of error %"PRIu32"", - subsystem_name, status); - } - -#endif - - if (status) - return status; - - if (rdpsnd->device) - { - if (!rdpsnd_set_subsystem(rdpsnd, subsystem_name) - || !rdpsnd_set_device_name(rdpsnd, device_name)) + if (!rdpsnd_set_subsystem(rdpsnd, subsystem_name) || + !rdpsnd_set_device_name(rdpsnd, device_name)) return CHANNEL_RC_NO_MEMORY; + + break; } - } - if (!rdpsnd->device) - { - WLog_ERR(TAG, "no sound device."); - return CHANNEL_RC_INITIALIZATION_ERROR; - } - - if (!rdpsnd->device->DisableConfirmThread) - { - rdpsnd->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - - if (!rdpsnd->stopEvent) - { - WLog_ERR(TAG, "CreateEvent failed!"); + if (!rdpsnd->device || status) return CHANNEL_RC_INITIALIZATION_ERROR; - } - - rdpsnd->ScheduleThread = CreateThread(NULL, 0, - rdpsnd_schedule_thread, - (void*) rdpsnd, 0, NULL); - - if (!rdpsnd->ScheduleThread) - { - WLog_ERR(TAG, "CreateThread failed!"); - return CHANNEL_RC_INITIALIZATION_ERROR; - } } return CHANNEL_RC_OK; @@ -1130,19 +897,7 @@ static UINT rdpsnd_process_connect(rdpsndPlugin* rdpsnd) static void rdpsnd_process_disconnect(rdpsndPlugin* rdpsnd) { - if (rdpsnd->ScheduleThread) - { - SetEvent(rdpsnd->stopEvent); - - if (WaitForSingleObject(rdpsnd->ScheduleThread, INFINITE) == WAIT_FAILED) - { - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", GetLastError()); - return; - } - - CloseHandle(rdpsnd->ScheduleThread); - CloseHandle(rdpsnd->stopEvent); - } + rdpsnd_recv_close_pdu(rdpsnd); } /** @@ -1152,13 +907,9 @@ static void rdpsnd_process_disconnect(rdpsndPlugin* rdpsnd) */ UINT rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s) { - UINT status; + UINT status = CHANNEL_RC_BAD_INIT_HANDLE; - if (!rdpsnd) - { - status = CHANNEL_RC_BAD_INIT_HANDLE; - } - else + if (rdpsnd) { status = rdpsnd->channelEntryPoints.pVirtualChannelWriteEx(rdpsnd->InitHandle, rdpsnd->OpenHandle, Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s); @@ -1182,54 +933,34 @@ UINT rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s) static UINT 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 CHANNEL_RC_OK; - } if (dataFlags & CHANNEL_FLAG_FIRST) { - if (plugin->data_in != NULL) - Stream_Free(plugin->data_in, TRUE); - - plugin->data_in = Stream_New(NULL, totalLength); - if (!plugin->data_in) - { - WLog_ERR(TAG, "Stream_New failed!"); - return CHANNEL_RC_NO_MEMORY; - } + plugin->data_in = StreamPool_Take(plugin->pool, totalLength); + + Stream_SetPosition(plugin->data_in, 0); } - s = plugin->data_in; - - if (!Stream_EnsureRemainingCapacity(s, (int) dataLength)) - { - WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + if (!Stream_EnsureRemainingCapacity(plugin->data_in, dataLength)) return CHANNEL_RC_NO_MEMORY; - } - Stream_Write(s, pData, dataLength); + Stream_Write(plugin->data_in, pData, dataLength); if (dataFlags & CHANNEL_FLAG_LAST) { - if (Stream_Capacity(s) != Stream_GetPosition(s)) + Stream_SealLength(plugin->data_in); + Stream_SetPosition(plugin->data_in, 0); + + if (!Queue_Enqueue(plugin->queue, plugin->data_in)) { - WLog_ERR(TAG, "rdpsnd_virtual_channel_event_data_received: read error"); + WLog_ERR(TAG, "Queue_Enqueue failed!"); return ERROR_INTERNAL_ERROR; } plugin->data_in = NULL; - Stream_SealLength(s); - Stream_SetPosition(s, 0); - - if (!MessageQueue_Post(plugin->MsgPipe->In, NULL, 0, (void*) s, NULL)) - { - WLog_ERR(TAG, "MessageQueue_Post failed!"); - return ERROR_INTERNAL_ERROR; - } } return CHANNEL_RC_OK; @@ -1259,7 +990,6 @@ static VOID VCAPITYPE rdpsnd_virtual_channel_open_event_ex(LPVOID lpUserParam, D break; case CHANNEL_EVENT_WRITE_COMPLETE: - Stream_Free((wStream*) pData, TRUE); break; case CHANNEL_EVENT_USER: @@ -1273,10 +1003,10 @@ static VOID VCAPITYPE rdpsnd_virtual_channel_open_event_ex(LPVOID lpUserParam, D static DWORD WINAPI rdpsnd_virtual_channel_client_thread(LPVOID arg) { - wStream* data; - wMessage message; + BOOL running = TRUE; rdpsndPlugin* rdpsnd = (rdpsndPlugin*) arg; - UINT error; + DWORD error = CHANNEL_RC_OK; + HANDLE events[2]; if ((error = rdpsnd_process_connect(rdpsnd))) { @@ -1284,36 +1014,32 @@ static DWORD WINAPI rdpsnd_virtual_channel_client_thread(LPVOID arg) goto out; } - while (1) + events[1] = rdpsnd->stopEvent; + events[0] = Queue_Event(rdpsnd->queue); + + do { - if (!MessageQueue_Wait(rdpsnd->MsgPipe->In)) + const DWORD status = WaitForMultipleObjects(ARRAYSIZE(events), events, FALSE, INFINITE); + + switch (status) { - WLog_ERR(TAG, "MessageQueue_Wait failed!"); - error = ERROR_INTERNAL_ERROR; - break; - } - - if (!MessageQueue_Peek(rdpsnd->MsgPipe->In, &message, TRUE)) - { - WLog_ERR(TAG, "MessageQueue_Peek failed!"); - error = ERROR_INTERNAL_ERROR; - break; - } - - if (message.id == WMQ_QUIT) - break; - - if (message.id == 0) - { - data = (wStream*) message.wParam; - - if ((error = rdpsnd_recv_pdu(rdpsnd, data))) - { - WLog_ERR(TAG, "error treating sound channel message"); + case WAIT_OBJECT_0: + { + wStream* s = Queue_Dequeue(rdpsnd->queue); + error = rdpsnd_recv_pdu(rdpsnd, s); + } + break; + + case WAIT_OBJECT_0 + 1: + running = FALSE; + break; + + default: + error = status; break; - } } } + while ((error == CHANNEL_RC_OK) && running); out: @@ -1322,10 +1048,32 @@ out: "rdpsnd_virtual_channel_client_thread reported an error"); rdpsnd_process_disconnect(rdpsnd); - ExitThread(error); + ExitThread((DWORD)error); return error; } +/* Called during cleanup. + * All streams still in the queue have been removed + * from the streampool and nead cleanup. */ +static void rdpsnd_queue_free(void* data) +{ + wStream* s = (wStream*)data; + Stream_Free(s, TRUE); +} + +static UINT rdpsnd_virtual_channel_event_initialized(rdpsndPlugin* rdpsnd, + LPVOID pData, UINT32 dataLength) +{ + rdpsnd->stopEvent = CreateEventA(NULL, TRUE, FALSE, "rdpsnd->stopEvent"); + + if (!rdpsnd->stopEvent) + goto fail; + + return CHANNEL_RC_OK; +fail: + return ERROR_INTERNAL_ERROR; +} + /** * Function description * @@ -1346,27 +1094,43 @@ static UINT rdpsnd_virtual_channel_event_connected(rdpsndPlugin* rdpsnd, return status; } - rdpsnd->MsgPipe = MessagePipe_New(); + rdpsnd->dsp_context = freerdp_dsp_context_new(FALSE); - if (!rdpsnd->MsgPipe) - { - WLog_ERR(TAG, "unable to create message pipe"); - return CHANNEL_RC_NO_MEMORY; - } + if (!rdpsnd->dsp_context) + goto fail; + rdpsnd->queue = Queue_New(TRUE, 32, 2); + + if (!rdpsnd->queue) + goto fail; + + rdpsnd->queue->object.fnObjectFree = rdpsnd_queue_free; + rdpsnd->pool = StreamPool_New(TRUE, 4096); + + if (!rdpsnd->pool) + goto fail; + + ResetEvent(rdpsnd->stopEvent); rdpsnd->thread = CreateThread(NULL, 0, - rdpsnd_virtual_channel_client_thread, (void*) rdpsnd, + rdpsnd_virtual_channel_client_thread, (void*) rdpsnd, 0, NULL); if (!rdpsnd->thread) - { - WLog_ERR(TAG, "unable to create thread"); - MessagePipe_Free(rdpsnd->MsgPipe); - rdpsnd->MsgPipe = NULL; - return ERROR_INTERNAL_ERROR; - } + goto fail; return CHANNEL_RC_OK; +fail: + freerdp_dsp_context_free(rdpsnd->dsp_context); + StreamPool_Free(rdpsnd->pool); + Queue_Free(rdpsnd->queue); + + if (rdpsnd->stopEvent) + CloseHandle(rdpsnd->stopEvent); + + if (rdpsnd->thread) + CloseHandle(rdpsnd->thread); + + return CHANNEL_RC_NO_MEMORY; } /** @@ -1377,7 +1141,11 @@ static UINT rdpsnd_virtual_channel_event_connected(rdpsndPlugin* rdpsnd, static UINT rdpsnd_virtual_channel_event_disconnected(rdpsndPlugin* rdpsnd) { UINT error; - MessagePipe_PostQuit(rdpsnd->MsgPipe, 0); + + if (rdpsnd->OpenHandle == 0) + return CHANNEL_RC_OK; + + SetEvent(rdpsnd->stopEvent); if (WaitForSingleObject(rdpsnd->thread, INFINITE) == WAIT_FAILED) { @@ -1387,7 +1155,6 @@ static UINT rdpsnd_virtual_channel_event_disconnected(rdpsndPlugin* rdpsnd) } CloseHandle(rdpsnd->thread); - rdpsnd->thread = NULL; error = rdpsnd->channelEntryPoints.pVirtualChannelCloseEx(rdpsnd->InitHandle, rdpsnd->OpenHandle); if (CHANNEL_RC_OK != error) @@ -1398,19 +1165,14 @@ static UINT rdpsnd_virtual_channel_event_disconnected(rdpsndPlugin* rdpsnd) } rdpsnd->OpenHandle = 0; - - if (rdpsnd->data_in) - { - Stream_Free(rdpsnd->data_in, TRUE); - rdpsnd->data_in = NULL; - } - - MessagePipe_Free(rdpsnd->MsgPipe); - rdpsnd->MsgPipe = NULL; - rdpsnd_free_audio_formats(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats); + freerdp_dsp_context_free(rdpsnd->dsp_context); + StreamPool_Return(rdpsnd->pool, rdpsnd->data_in); + StreamPool_Free(rdpsnd->pool); + Queue_Free(rdpsnd->queue); + audio_formats_free(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats); rdpsnd->NumberOfClientFormats = 0; rdpsnd->ClientFormats = NULL; - rdpsnd_free_audio_formats(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats); + audio_formats_free(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats); rdpsnd->NumberOfServerFormats = 0; rdpsnd->ServerFormats = NULL; @@ -1420,24 +1182,20 @@ static UINT rdpsnd_virtual_channel_event_disconnected(rdpsndPlugin* rdpsnd) rdpsnd->device = NULL; } - if (rdpsnd->subsystem) - { - free(rdpsnd->subsystem); - rdpsnd->subsystem = NULL; - } - - if (rdpsnd->device_name) - { - free(rdpsnd->device_name); - rdpsnd->device_name = NULL; - } - return CHANNEL_RC_OK; } static void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd) { - rdpsnd->InitHandle = 0; + if (rdpsnd) + { + audio_formats_free(rdpsnd->fixed_format, 1); + free(rdpsnd->subsystem); + free(rdpsnd->device_name); + CloseHandle(rdpsnd->stopEvent); + rdpsnd->InitHandle = 0; + } + free(rdpsnd); } @@ -1455,6 +1213,13 @@ static VOID VCAPITYPE rdpsnd_virtual_channel_init_event_ex(LPVOID lpUserParam, L switch (event) { + case CHANNEL_EVENT_INITIALIZED: + if ((error = rdpsnd_virtual_channel_event_initialized(plugin, pData, dataLength))) + WLog_ERR(TAG, "rdpsnd_virtual_channel_event_initialized failed with error %"PRIu32"!", + error); + + 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"!", @@ -1500,31 +1265,18 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx; if (!pEntryPoints) - { return FALSE; - } rdpsnd = (rdpsndPlugin*) calloc(1, sizeof(rdpsndPlugin)); if (!rdpsnd) - { - WLog_ERR(TAG, "calloc failed!"); return FALSE; - } rdpsnd->attached = TRUE; -#if !defined(_WIN32) && !defined(ANDROID) - { - sigset_t mask; - sigemptyset(&mask); - sigaddset(&mask, SIGIO); - pthread_sigmask(SIG_BLOCK, &mask, NULL); - } -#endif rdpsnd->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP; - strcpy(rdpsnd->channelDef.name, "rdpsnd"); + sprintf_s(rdpsnd->channelDef.name, ARRAYSIZE(rdpsnd->channelDef.name), "rdpsnd"); pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*) pEntryPoints; if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) && @@ -1533,6 +1285,14 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p rdpsnd->rdpcontext = pEntryPointsEx->context; } + rdpsnd->fixed_format = audio_format_new(); + + if (!rdpsnd->fixed_format) + { + free(rdpsnd); + return FALSE; + } + rdpsnd->log = WLog_Get("com.freerdp.channels.rdpsnd.client"); CopyMemory(&(rdpsnd->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)); diff --git a/channels/rdpsnd/client/rdpsnd_main.h b/channels/rdpsnd/client/rdpsnd_main.h index 81cb426..aee8658 100644 --- a/channels/rdpsnd/client/rdpsnd_main.h +++ b/channels/rdpsnd/client/rdpsnd_main.h @@ -35,6 +35,4 @@ #define DEBUG_SND(...) do { } while (0) #endif -UINT rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s); - #endif /* FREERDP_CHANNEL_RDPSND_CLIENT_MAIN_H */ diff --git a/channels/rdpsnd/client/winmm/rdpsnd_winmm.c b/channels/rdpsnd/client/winmm/rdpsnd_winmm.c index 9c24c43..c61e02c 100644 --- a/channels/rdpsnd/client/winmm/rdpsnd_winmm.c +++ b/channels/rdpsnd/client/winmm/rdpsnd_winmm.c @@ -36,7 +36,6 @@ #include #include -#include #include #include "rdpsnd_main.h" @@ -49,15 +48,14 @@ struct rdpsnd_winmm_plugin HWAVEOUT hWaveOut; WAVEFORMATEX format; - int wformat; - int block_size; UINT32 volume; - FREERDP_DSP_CONTEXT* dsp_context; + HANDLE next; }; static BOOL rdpsnd_winmm_convert_format(const AUDIO_FORMAT* in, WAVEFORMATEX* out) { - BOOL result = FALSE; + if (!in || !out) + return FALSE; ZeroMemory(out, sizeof(WAVEFORMATEX)); out->wFormatTag = WAVE_FORMAT_PCM; @@ -68,40 +66,31 @@ static BOOL rdpsnd_winmm_convert_format(const AUDIO_FORMAT* in, WAVEFORMATEX* ou { case WAVE_FORMAT_PCM: out->wBitsPerSample = in->wBitsPerSample; - result = TRUE; break; - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - out->wBitsPerSample = 16; - result = TRUE; - break; + default: + return FALSE; } out->nBlockAlign = out->nChannels * out->wBitsPerSample / 8; out->nAvgBytesPerSec = out->nSamplesPerSec * out->nBlockAlign; - - return result; -} - -static BOOL rdpsnd_winmm_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) -{ - rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; - - if (format) - { - if (!rdpsnd_winmm_convert_format(format, &winmm->format)) - return FALSE; - - winmm->wformat = format->wFormatTag; - winmm->block_size = format->nBlockAlign; - } return TRUE; } -static void CALLBACK rdpsnd_winmm_callback_function(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) +static BOOL rdpsnd_winmm_set_format(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, + UINT32 latency) +{ + rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; + + if (!rdpsnd_winmm_convert_format(format, &winmm->format)) + return FALSE; + + return TRUE; +} + +static void CALLBACK rdpsnd_winmm_callback_function(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, + DWORD_PTR dwParam1, DWORD_PTR dwParam2) { - RDPSND_WAVE* wave; LPWAVEHDR lpWaveHdr; rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) dwInstance; @@ -110,42 +99,27 @@ static void CALLBACK rdpsnd_winmm_callback_function(HWAVEOUT hwo, UINT uMsg, DWO case MM_WOM_OPEN: WLog_DBG(TAG, "MM_WOM_OPEN"); break; - + case MM_WOM_CLOSE: WLog_DBG(TAG, "MM_WOM_CLOSE"); + SetEvent(winmm->next); break; case MM_WOM_DONE: - { - UINT32 wTimeDelta; - lpWaveHdr = (LPWAVEHDR) dwParam1; + WLog_DBG(TAG, "MM_WOM_DONE"); + lpWaveHdr = (LPWAVEHDR) dwParam1; + free(lpWaveHdr); + SetEvent(winmm->next); + break; - if (!lpWaveHdr) - return; - - wave = (RDPSND_WAVE*) lpWaveHdr->dwUser; - - if (!wave) - return; - - WLog_DBG(TAG, "MM_WOM_DONE: dwBufferLength: %"PRIu32" cBlockNo: %"PRIu8"", - lpWaveHdr->dwBufferLength, wave->cBlockNo); - wave->wLocalTimeB = GetTickCount(); - wTimeDelta = wave->wLocalTimeB - wave->wLocalTimeA; - wave->wTimeStampB = wave->wTimeStampA + wTimeDelta; - - winmm->device.WaveConfirm(&(winmm->device), wave); - - free(lpWaveHdr->lpData); - free(lpWaveHdr); - - free(wave); - } + default: + WLog_DBG(TAG, "UNKNOWN [0x%08"PRIx32"]", uMsg); break; } } -static BOOL rdpsnd_winmm_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) +static BOOL rdpsnd_winmm_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, + UINT32 latency) { MMRESULT mmResult; rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; @@ -153,15 +127,15 @@ static BOOL rdpsnd_winmm_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, if (winmm->hWaveOut) return TRUE; - rdpsnd_winmm_set_format(device, format, latency); - freerdp_dsp_context_reset_adpcm(winmm->dsp_context); + if (!rdpsnd_winmm_set_format(device, format, latency)) + return FALSE; mmResult = waveOutOpen(&winmm->hWaveOut, WAVE_MAPPER, &winmm->format, - (DWORD_PTR) rdpsnd_winmm_callback_function, (DWORD_PTR) winmm, CALLBACK_FUNCTION); + (DWORD_PTR) rdpsnd_winmm_callback_function, (DWORD_PTR) winmm, CALLBACK_FUNCTION); if (mmResult != MMSYSERR_NOERROR) { - WLog_ERR(TAG, "waveOutOpen failed: %"PRIu32"", mmResult); + WLog_ERR(TAG, "waveOutOpen failed: %"PRIu32"", mmResult); return FALSE; } @@ -169,7 +143,7 @@ static BOOL rdpsnd_winmm_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, if (mmResult != MMSYSERR_NOERROR) { - WLog_ERR(TAG, "waveOutSetVolume failed: %"PRIu32"", mmResult); + WLog_ERR(TAG, "waveOutSetVolume failed: %"PRIu32"", mmResult); return FALSE; } @@ -184,14 +158,13 @@ static void rdpsnd_winmm_close(rdpsndDevicePlugin* device) if (winmm->hWaveOut) { mmResult = waveOutReset(winmm->hWaveOut); - mmResult = waveOutClose(winmm->hWaveOut); if (mmResult != MMSYSERR_NOERROR) { WLog_ERR(TAG, "waveOutClose failure: %"PRIu32"", mmResult); } - + winmm->hWaveOut = NULL; } } @@ -203,14 +176,12 @@ static void rdpsnd_winmm_free(rdpsndDevicePlugin* device) if (winmm) { rdpsnd_winmm_close(device); - - freerdp_dsp_context_free(winmm->dsp_context); - + CloseHandle(winmm->next); free(winmm); } } -static BOOL rdpsnd_winmm_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT* format) +static BOOL rdpsnd_winmm_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format) { MMRESULT result; WAVEFORMATEX out; @@ -231,9 +202,7 @@ static UINT32 rdpsnd_winmm_get_volume(rdpsndDevicePlugin* device) DWORD dwVolume; UINT16 dwVolumeLeft; UINT16 dwVolumeRight; - rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; - dwVolumeLeft = ((50 * 0xFFFF) / 100); /* 50% */ dwVolumeRight = ((50 * 0xFFFF) / 100); /* 50% */ dwVolume = (dwVolumeLeft << 16) | dwVolumeRight; @@ -242,14 +211,12 @@ static UINT32 rdpsnd_winmm_get_volume(rdpsndDevicePlugin* device) return dwVolume; waveOutGetVolume(winmm->hWaveOut, &dwVolume); - return dwVolume; } static BOOL rdpsnd_winmm_set_volume(rdpsndDevicePlugin* device, UINT32 value) { rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; - winmm->volume = value; if (!winmm->hWaveOut) @@ -258,72 +225,38 @@ static BOOL rdpsnd_winmm_set_volume(rdpsndDevicePlugin* device, UINT32 value) return (waveOutSetVolume(winmm->hWaveOut, value) == MMSYSERR_NOERROR); } -static BOOL rdpsnd_winmm_wave_decode(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) +static void rdpsnd_winmm_start(rdpsndDevicePlugin* device) { - int length; - BYTE* data; - rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; - - if (winmm->wformat == WAVE_FORMAT_ADPCM) - { - winmm->dsp_context->decode_ms_adpcm(winmm->dsp_context, - wave->data, wave->length, winmm->format.nChannels, winmm->block_size); - length = winmm->dsp_context->adpcm_size; - data = winmm->dsp_context->adpcm_buffer; - } - else if (winmm->wformat == WAVE_FORMAT_DVI_ADPCM) - { - winmm->dsp_context->decode_ima_adpcm(winmm->dsp_context, - wave->data, wave->length, winmm->format.nChannels, winmm->block_size); - length = winmm->dsp_context->adpcm_size; - data = winmm->dsp_context->adpcm_buffer; - } - else - { - length = wave->length; - data = wave->data; - } - - wave->data = (BYTE*) malloc(length); - if (!wave->data) - return FALSE; - CopyMemory(wave->data, data, length); - wave->length = length; - - return TRUE; + //rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; } -void rdpsnd_winmm_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) +static UINT rdpsnd_winmm_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size) { MMRESULT mmResult; LPWAVEHDR lpWaveHdr; rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; if (!winmm->hWaveOut) - return; - - wave->AutoConfirm = FALSE; + return 0; lpWaveHdr = (LPWAVEHDR) malloc(sizeof(WAVEHDR)); if (!lpWaveHdr) - return; + return 0; ZeroMemory(lpWaveHdr, sizeof(WAVEHDR)); - lpWaveHdr->dwFlags = 0; lpWaveHdr->dwLoops = 0; - lpWaveHdr->lpData = (LPSTR) wave->data; - lpWaveHdr->dwBufferLength = wave->length; - lpWaveHdr->dwUser = (DWORD_PTR) wave; + lpWaveHdr->lpData = (LPSTR) data; + lpWaveHdr->dwBufferLength = size; + lpWaveHdr->dwUser = NULL; lpWaveHdr->lpNext = NULL; - mmResult = waveOutPrepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR)); if (mmResult != MMSYSERR_NOERROR) { WLog_ERR(TAG, "waveOutPrepareHeader failure: %"PRIu32"", mmResult); - return; + return 0; } mmResult = waveOutWrite(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR)); @@ -333,18 +266,15 @@ void rdpsnd_winmm_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) WLog_ERR(TAG, "waveOutWrite failure: %"PRIu32"", mmResult); waveOutUnprepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR)); free(lpWaveHdr); - return; + return 0; } -} -static void rdpsnd_winmm_start(rdpsndDevicePlugin* device) -{ - //rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; + WaitForSingleObject(winmm->next, INFINITE); + return 10; /* TODO: Get real latencry in [ms] */ } static void rdpsnd_winmm_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* args) { - } #ifdef BUILTIN_CHANNELS @@ -362,38 +292,30 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p { ADDIN_ARGV* args; rdpsndWinmmPlugin* winmm; - winmm = (rdpsndWinmmPlugin*) calloc(1, sizeof(rdpsndWinmmPlugin)); if (!winmm) return CHANNEL_RC_NO_MEMORY; - winmm->device.DisableConfirmThread = TRUE; - winmm->device.Open = rdpsnd_winmm_open; winmm->device.FormatSupported = rdpsnd_winmm_format_supported; - winmm->device.SetFormat = rdpsnd_winmm_set_format; winmm->device.GetVolume = rdpsnd_winmm_get_volume; winmm->device.SetVolume = rdpsnd_winmm_set_volume; - winmm->device.WaveDecode = rdpsnd_winmm_wave_decode; - winmm->device.WavePlay = rdpsnd_winmm_wave_play; winmm->device.Start = rdpsnd_winmm_start; + winmm->device.Play = rdpsnd_winmm_play; winmm->device.Close = rdpsnd_winmm_close; winmm->device.Free = rdpsnd_winmm_free; + winmm->next = CreateEventA(NULL, FALSE, FALSE, "winmm-play-event"); - args = pEntryPoints->args; - rdpsnd_winmm_parse_addin_args((rdpsndDevicePlugin*) winmm, args); - - winmm->dsp_context = freerdp_dsp_context_new(); - if (!winmm->dsp_context) + if (!winmm->next) { free(winmm); return CHANNEL_RC_NO_MEMORY; } + args = pEntryPoints->args; + rdpsnd_winmm_parse_addin_args((rdpsndDevicePlugin*) winmm, args); winmm->volume = 0xFFFFFFFF; - pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) winmm); - return CHANNEL_RC_OK; } diff --git a/channels/rdpsnd/common/CMakeLists.txt b/channels/rdpsnd/common/CMakeLists.txt new file mode 100644 index 0000000..32fa918 --- /dev/null +++ b/channels/rdpsnd/common/CMakeLists.txt @@ -0,0 +1,24 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2018 Armin Novak +# Copyright 2018 Thincast Technologies GmbH +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set(SRCS + rdpsnd_common.h + rdpsnd_common.c) + +# Library currently header only +#add_library(rdpsnd-common STATIC ${SRCS}) diff --git a/channels/rdpsnd/common/rdpsnd_common.h b/channels/rdpsnd/common/rdpsnd_common.h new file mode 100644 index 0000000..6afcbc7 --- /dev/null +++ b/channels/rdpsnd/common/rdpsnd_common.h @@ -0,0 +1,43 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Server Audio Virtual Channel + * + * Copyright 2018 Armin Novak + * Copyright 2018 Thincast Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNEL_RDPSND_COMMON_MAIN_H +#define FREERDP_CHANNEL_RDPSND_COMMON_MAIN_H + +#include +#include +#include + +#include +#include +#include +#include + +typedef enum +{ + CHANNEL_VERSION_WIN_XP = 0x02, + CHANNEL_VERSION_WIN_XP_SP1 = 0x05, + CHANNEL_VERSION_WIN_VISTA = 0x05, + CHANNEL_VERSION_WIN_7 = 0x06, + CHANNEL_VERSION_WIN_8 = 0x08, + CHANNEL_VERSION_WIN_MAX = CHANNEL_VERSION_WIN_8 +} RdpSndChannelVersion; + +#endif /* FREERDP_CHANNEL_RDPSND_COMMON_MAIN_H */ diff --git a/channels/rdpsnd/server/CMakeLists.txt b/channels/rdpsnd/server/CMakeLists.txt index 62d57be..9df47f2 100644 --- a/channels/rdpsnd/server/CMakeLists.txt +++ b/channels/rdpsnd/server/CMakeLists.txt @@ -23,9 +23,4 @@ set(${MODULE_PREFIX}_SRCS add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") - - -target_link_libraries(${MODULE_NAME} freerdp) - - set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/rdpsnd/server/rdpsnd_main.c b/channels/rdpsnd/server/rdpsnd_main.c index b144e53..53d4d5c 100644 --- a/channels/rdpsnd/server/rdpsnd_main.c +++ b/channels/rdpsnd/server/rdpsnd_main.c @@ -33,6 +33,7 @@ #include +#include "rdpsnd_common.h" #include "rdpsnd_main.h" /** @@ -40,11 +41,11 @@ * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s) +static UINT rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s) { size_t pos; UINT16 i; - BOOL status; + BOOL status = FALSE; ULONG written; Stream_Write_UINT8(s, SNDC_FORMATS); Stream_Write_UINT8(s, 0); @@ -55,30 +56,17 @@ UINT rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s) Stream_Write_UINT16(s, 0); /* wDGramPort */ Stream_Write_UINT16(s, context->num_server_formats); /* wNumberOfFormats */ Stream_Write_UINT8(s, context->block_no); /* cLastBlockConfirmed */ - Stream_Write_UINT16(s, 0x06); /* wVersion */ + Stream_Write_UINT16(s, CHANNEL_VERSION_WIN_MAX); /* wVersion */ Stream_Write_UINT8(s, 0); /* bPad */ for (i = 0; i < context->num_server_formats; i++) { - Stream_Write_UINT16(s, - context->server_formats[i].wFormatTag); /* wFormatTag (WAVE_FORMAT_PCM) */ - Stream_Write_UINT16(s, context->server_formats[i].nChannels); /* nChannels */ - Stream_Write_UINT32(s, - context->server_formats[i].nSamplesPerSec); /* nSamplesPerSec */ - Stream_Write_UINT32(s, context->server_formats[i].nSamplesPerSec * - context->server_formats[i].nChannels * - context->server_formats[i].wBitsPerSample / 8); /* nAvgBytesPerSec */ - Stream_Write_UINT16(s, - context->server_formats[i].nBlockAlign); /* nBlockAlign */ - Stream_Write_UINT16(s, - context->server_formats[i].wBitsPerSample); /* wBitsPerSample */ - Stream_Write_UINT16(s, context->server_formats[i].cbSize); /* cbSize */ + AUDIO_FORMAT format = context->server_formats[i]; + // TODO: Eliminate this!!! + format.nAvgBytesPerSec = format.nSamplesPerSec * format.nChannels * format.wBitsPerSample / 8; - if (context->server_formats[i].cbSize > 0) - { - Stream_Write(s, context->server_formats[i].data, - context->server_formats[i].cbSize); - } + if (!audio_format_write(s, &format)) + goto fail; } pos = Stream_GetPosition(s); @@ -88,6 +76,7 @@ UINT rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s) status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written); Stream_SetPosition(s, 0); +fail: return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; } @@ -149,7 +138,7 @@ static UINT rdpsnd_server_recv_quality_mode(RdpsndServerContext* context, */ static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) { - int i, num_known_format = 0; + UINT16 i, num_known_format = 0; UINT32 flags, vol, pitch; UINT16 udpPort; BYTE lastblock; @@ -183,8 +172,7 @@ static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) return ERROR_INTERNAL_ERROR; } - context->client_formats = (AUDIO_FORMAT*)calloc(context->num_client_formats, - sizeof(AUDIO_FORMAT)); + context->client_formats = audio_formats_new(context->num_client_formats); if (!context->client_formats) { @@ -246,17 +234,10 @@ static DWORD WINAPI rdpsnd_server_thread(LPVOID arg) RdpsndServerContext* context; UINT error = CHANNEL_RC_OK; context = (RdpsndServerContext*)arg; - nCount = 0; events[nCount++] = context->priv->channelEvent; events[nCount++] = context->priv->StopEvent; - if ((error = rdpsnd_server_send_formats(context, context->priv->rdpsnd_pdu))) - { - WLog_ERR(TAG, "rdpsnd_server_send_formats failed with error %"PRIu32"", error); - goto out; - } - while (TRUE) { status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); @@ -287,8 +268,6 @@ static DWORD WINAPI rdpsnd_server_thread(LPVOID arg) } } -out: - if (error && context->rdpcontext) setChannelError(context->rdpcontext, error, "rdpsnd_server_thread reported an error"); @@ -315,24 +294,24 @@ static UINT rdpsnd_server_initialize(RdpsndServerContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rdpsnd_server_select_format(RdpsndServerContext* context, - int client_format_index) + UINT16 client_format_index) { int bs; int out_buffer_size; AUDIO_FORMAT* format; UINT error = CHANNEL_RC_OK; - if (client_format_index < 0 - || client_format_index >= context->num_client_formats) + if ((client_format_index >= context->num_client_formats) + || (!context->src_format)) { WLog_ERR(TAG, "index %d is not correct.", client_format_index); return ERROR_INVALID_DATA; } EnterCriticalSection(&context->priv->lock); - context->priv->src_bytes_per_sample = context->src_format.wBitsPerSample / 8; + context->priv->src_bytes_per_sample = context->src_format->wBitsPerSample / 8; context->priv->src_bytes_per_frame = context->priv->src_bytes_per_sample * - context->src_format.nChannels; + context->src_format->nChannels; context->selected_client_format = client_format_index; format = &context->client_formats[client_format_index]; @@ -346,7 +325,7 @@ static UINT rdpsnd_server_select_format(RdpsndServerContext* context, if (context->latency <= 0) context->latency = 50; - context->priv->out_frames = context->src_format.nSamplesPerSec * + context->priv->out_frames = context->src_format->nSamplesPerSec * context->latency / 1000; if (context->priv->out_frames < 1) @@ -393,120 +372,101 @@ static UINT rdpsnd_server_select_format(RdpsndServerContext* context, context->priv->out_buffer_size = out_buffer_size; } - freerdp_dsp_context_reset_adpcm(context->priv->dsp_context); + freerdp_dsp_context_reset(context->priv->dsp_context, format); out: LeaveCriticalSection(&context->priv->lock); return error; } +static BOOL rdpsnd_server_align_wave_pdu(wStream* s, UINT32 alignment) +{ + size_t size; + Stream_SealLength(s); + size = Stream_Length(s); + + if ((size % alignment) != 0) + { + size_t offset = alignment - size % alignment; + + if (!Stream_EnsureRemainingCapacity(s, offset)) + return FALSE; + + Stream_Zero(s, offset); + } + + Stream_SealLength(s); + return TRUE; +} + /** * Function description * context->priv->lock should be obtained before calling this function * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, - UINT16 wTimestamp) +static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, + UINT16 wTimestamp) { - int size; - BYTE* src; - int frames; - int fill_size; - BOOL status; + size_t length; + size_t start, end = 0; + const BYTE* src; AUDIO_FORMAT* format; - int tbytes_per_frame; ULONG written; wStream* s = context->priv->rdpsnd_pdu; UINT error = CHANNEL_RC_OK; + + if (context->selected_client_format >= context->num_client_formats) + return ERROR_INTERNAL_ERROR; + format = &context->client_formats[context->selected_client_format]; - tbytes_per_frame = format->nChannels * context->priv->src_bytes_per_sample; - - if ((format->nSamplesPerSec == context->src_format.nSamplesPerSec) && - (format->nChannels == context->src_format.nChannels)) - { - src = context->priv->out_buffer; - frames = context->priv->out_pending_frames; - } - else - { - context->priv->dsp_context->resample(context->priv->dsp_context, - context->priv->out_buffer, - context->priv->src_bytes_per_sample, context->src_format.nChannels, - context->src_format.nSamplesPerSec, context->priv->out_pending_frames, - format->nChannels, format->nSamplesPerSec); - frames = context->priv->dsp_context->resampled_frames; - src = context->priv->dsp_context->resampled_buffer; - } - - size = frames * tbytes_per_frame; - - if (format->wFormatTag == WAVE_FORMAT_DVI_ADPCM) - { - context->priv->dsp_context->encode_ima_adpcm(context->priv->dsp_context, - src, size, format->nChannels, format->nBlockAlign); - src = context->priv->dsp_context->adpcm_buffer; - size = context->priv->dsp_context->adpcm_size; - } - else if (format->wFormatTag == WAVE_FORMAT_ADPCM) - { - context->priv->dsp_context->encode_ms_adpcm(context->priv->dsp_context, - src, size, format->nChannels, format->nBlockAlign); - src = context->priv->dsp_context->adpcm_buffer; - size = context->priv->dsp_context->adpcm_size; - } - - context->block_no = (context->block_no + 1) % 256; - /* Fill to nBlockAlign for the last audio packet */ - fill_size = 0; - - if ((format->wFormatTag == WAVE_FORMAT_DVI_ADPCM - || format->wFormatTag == WAVE_FORMAT_ADPCM) && - (context->priv->out_pending_frames < context->priv->out_frames) - && ((size % format->nBlockAlign) != 0)) - { - fill_size = format->nBlockAlign - (size % format->nBlockAlign); - } - /* WaveInfo PDU */ Stream_SetPosition(s, 0); Stream_Write_UINT8(s, SNDC_WAVE); /* msgType */ Stream_Write_UINT8(s, 0); /* bPad */ - Stream_Write_UINT16(s, size + fill_size + 8); /* BodySize */ + Stream_Write_UINT16(s, 0); /* BodySize */ Stream_Write_UINT16(s, wTimestamp); /* wTimeStamp */ Stream_Write_UINT16(s, context->selected_client_format); /* wFormatNo */ Stream_Write_UINT8(s, context->block_no); /* cBlockNo */ Stream_Seek(s, 3); /* bPad */ - Stream_Write(s, src, 4); - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written); + start = Stream_GetPosition(s); + src = context->priv->out_buffer; + length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame; - if (!status) + if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, src, length, s)) + return ERROR_INTERNAL_ERROR; + else + { + /* Set stream size */ + if (!rdpsnd_server_align_wave_pdu(s, format->nBlockAlign)) + return ERROR_INTERNAL_ERROR; + + end = Stream_GetPosition(s); + Stream_SetPosition(s, 2); + Stream_Write_UINT16(s, end - start + 8); + Stream_SetPosition(s, end); + context->block_no = (context->block_no + 1) % 256; + + if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, + (PCHAR) Stream_Buffer(s), start + 4, &written)) + { + WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); + error = ERROR_INTERNAL_ERROR; + } + } + + if (error != CHANNEL_RC_OK) { WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); error = ERROR_INTERNAL_ERROR; goto out; } - Stream_SetPosition(s, 0); - - /* Wave PDU */ - if (!Stream_EnsureRemainingCapacity(s, size + fill_size)) - { - WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto out; - } - + Stream_SetPosition(s, start); Stream_Write_UINT32(s, 0); /* bPad */ - Stream_Write(s, src + 4, size - 4); + Stream_SetPosition(s, start); - if (fill_size > 0) - Stream_Zero(s, fill_size); - - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written); - - if (!status) + if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, + (PCHAR) Stream_Pointer(s), end - start, &written)) { WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); error = ERROR_INTERNAL_ERROR; @@ -518,6 +478,80 @@ out: return error; } +/** + * Function description + * context->priv->lock should be obtained before calling this function + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, + UINT16 wTimestamp) +{ + size_t length; + size_t end = 0; + const BYTE* src; + AUDIO_FORMAT* format; + ULONG written; + wStream* s = context->priv->rdpsnd_pdu; + UINT error = CHANNEL_RC_OK; + + if (context->selected_client_format >= context->num_client_formats) + return ERROR_INTERNAL_ERROR; + + format = &context->client_formats[context->selected_client_format]; + /* WaveInfo PDU */ + Stream_SetPosition(s, 0); + Stream_Write_UINT8(s, SNDC_WAVE2); /* msgType */ + Stream_Write_UINT8(s, 0); /* bPad */ + Stream_Write_UINT16(s, 0); /* BodySize */ + Stream_Write_UINT16(s, wTimestamp); /* wTimeStamp */ + Stream_Write_UINT16(s, context->selected_client_format); /* wFormatNo */ + Stream_Write_UINT8(s, context->block_no); /* cBlockNo */ + Stream_Seek(s, 3); /* bPad */ + Stream_Write_UINT32(s, wTimestamp); /* dwAudioTimeStamp */ + src = context->priv->out_buffer; + length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame; + + if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, src, length, s)) + error = ERROR_INTERNAL_ERROR; + else + { + BOOL rc; + + /* Set stream size */ + if (!rdpsnd_server_align_wave_pdu(s, format->nBlockAlign)) + return ERROR_INTERNAL_ERROR; + + end = Stream_GetPosition(s); + Stream_SetPosition(s, 2); + Stream_Write_UINT16(s, end - 4); + context->block_no = (context->block_no + 1) % 256; + rc = WTSVirtualChannelWrite(context->priv->ChannelHandle, + (PCHAR) Stream_Buffer(s), end, &written); + + if (!rc || (end != written)) + { + WLog_ERR(TAG, "WTSVirtualChannelWrite failed! [stream length=%"PRIdz" - written=%"PRIu32, end, + written); + error = ERROR_INTERNAL_ERROR; + } + } + + Stream_SetPosition(s, 0); + context->priv->out_pending_frames = 0; + return error; +} + +/* Wrapper function to send WAVE or WAVE2 PDU depending on client connected */ +static UINT rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, + UINT16 wTimestamp) +{ + if (context->clientVersion >= CHANNEL_VERSION_WIN_8) + return rdpsnd_server_send_wave2_pdu(context, wTimestamp); + else + return rdpsnd_server_send_wave_pdu(context, wTimestamp); +} + /** * Function description * @@ -531,7 +565,7 @@ static UINT rdpsnd_server_send_samples(RdpsndServerContext* context, UINT error = CHANNEL_RC_OK; EnterCriticalSection(&context->priv->lock); - if (context->selected_client_format < 0) + if (context->selected_client_format >= context->num_client_formats) { /* It's possible while format negotiation has not been done */ WLog_WARN(TAG, "Drop samples because client format has not been negotiated."); @@ -578,7 +612,6 @@ static UINT rdpsnd_server_set_volume(RdpsndServerContext* context, int left, BOOL status; ULONG written; wStream* s = context->priv->rdpsnd_pdu; - Stream_Write_UINT8(s, SNDC_SETVOLUME); Stream_Write_UINT8(s, 0); Stream_Seek_UINT16(s); @@ -610,7 +643,7 @@ static UINT rdpsnd_server_close(RdpsndServerContext* context) if (context->priv->out_pending_frames > 0) { - if (context->selected_client_format < 0) + if (context->selected_client_format >= context->num_client_formats) { WLog_ERR(TAG, "Pending audio frame exists while no format selected."); error = ERROR_INVALID_DATA; @@ -626,7 +659,7 @@ static UINT rdpsnd_server_close(RdpsndServerContext* context) if (error) return error; - context->selected_client_format = -1; + context->selected_client_format = 0xFFFF; Stream_Write_UINT8(s, SNDC_CLOSE); Stream_Write_UINT8(s, 0); Stream_Seek_UINT16(s); @@ -690,6 +723,12 @@ static UINT rdpsnd_server_start(RdpsndServerContext* context) goto out_pdu; } + if ((error = rdpsnd_server_send_formats(context, context->priv->rdpsnd_pdu))) + { + WLog_ERR(TAG, "rdpsnd_server_send_formats failed with error %"PRIu32"", error); + goto out_lock; + } + if (priv->ownThread) { context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); @@ -701,7 +740,7 @@ static UINT rdpsnd_server_start(RdpsndServerContext* context) } context->priv->Thread = CreateThread(NULL, 0, - rdpsnd_server_thread, (void*) context, 0, NULL); + rdpsnd_server_thread, (void*) context, 0, NULL); if (!context->priv->Thread) { @@ -775,7 +814,7 @@ RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm) context->vcm = vcm; context->Start = rdpsnd_server_start; context->Stop = rdpsnd_server_stop; - context->selected_client_format = -1; + context->selected_client_format = 0xFFFF; context->Initialize = rdpsnd_server_initialize; context->SelectFormat = rdpsnd_server_select_format; context->SendSamples = rdpsnd_server_send_samples; @@ -790,7 +829,7 @@ RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm) goto out_free; } - priv->dsp_context = freerdp_dsp_context_new(); + priv->dsp_context = freerdp_dsp_context_new(TRUE); if (!priv->dsp_context) { @@ -927,7 +966,7 @@ UINT rdpsnd_server_handle_messages(RdpsndServerContext* context) case SNDC_FORMATS: ret = rdpsnd_server_recv_formats(context, s); - if ((ret == CHANNEL_RC_OK) && (context->clientVersion < 6)) + if ((ret == CHANNEL_RC_OK) && (context->clientVersion < CHANNEL_VERSION_WIN_7)) IFCALL(context->Activated, context); break; @@ -937,7 +976,7 @@ UINT rdpsnd_server_handle_messages(RdpsndServerContext* context) Stream_SetPosition(s, 0); /* in case the Activated callback tries to treat some messages */ - if ((ret == CHANNEL_RC_OK) && (context->clientVersion >= 6)) + if ((ret == CHANNEL_RC_OK) && (context->clientVersion >= CHANNEL_VERSION_WIN_7)) IFCALL(context->Activated, context); break; diff --git a/channels/remdesk/client/remdesk_main.c b/channels/remdesk/client/remdesk_main.c index d40c520..9252929 100644 --- a/channels/remdesk/client/remdesk_main.c +++ b/channels/remdesk/client/remdesk_main.c @@ -109,6 +109,7 @@ static UINT remdesk_generate_expert_blob(remdeskPlugin* remdesk) } remdesk->ExpertBlob = freerdp_assistance_construct_expert_blob(name, pass); + free(pass); if (!remdesk->ExpertBlob) { @@ -219,7 +220,7 @@ static UINT remdesk_prepare_ctl_header(REMDESK_CTL_HEADER* ctlHeader, UINT32 msgType, UINT32 msgSize) { ctlHeader->msgType = msgType; - strcpy(ctlHeader->ChannelName, REMDESK_CHANNEL_CTL_NAME); + sprintf_s(ctlHeader->ChannelName, ARRAYSIZE(ctlHeader->ChannelName), REMDESK_CHANNEL_CTL_NAME); ctlHeader->DataLength = 4 + msgSize; return CHANNEL_RC_OK; } @@ -788,7 +789,6 @@ static VOID VCAPITYPE remdesk_virtual_channel_open_event_ex(LPVOID lpUserParam, break; case CHANNEL_EVENT_WRITE_COMPLETE: - Stream_Free((wStream*) pData, TRUE); break; case CHANNEL_EVENT_USER: @@ -882,7 +882,7 @@ static UINT remdesk_virtual_channel_event_connected(remdeskPlugin* remdesk, } remdesk->thread = CreateThread(NULL, 0, - remdesk_virtual_channel_client_thread, (void*) remdesk, + remdesk_virtual_channel_client_thread, (void*) remdesk, 0, NULL); if (!remdesk->thread) @@ -908,6 +908,9 @@ static UINT remdesk_virtual_channel_event_disconnected(remdeskPlugin* remdesk) { UINT rc; + if (remdesk->OpenHandle == 0) + return CHANNEL_RC_OK; + if (MessageQueue_PostQuit(remdesk->queue, 0) && (WaitForSingleObject(remdesk->thread, INFINITE) == WAIT_FAILED)) { @@ -1019,7 +1022,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL; - strcpy(remdesk->channelDef.name, "remdesk"); + sprintf_s(remdesk->channelDef.name, ARRAYSIZE(remdesk->channelDef.name), "remdesk"); remdesk->Version = 2; pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*) pEntryPoints; diff --git a/channels/remdesk/server/remdesk_main.c b/channels/remdesk/server/remdesk_main.c index 16e7453..447ede4 100644 --- a/channels/remdesk/server/remdesk_main.c +++ b/channels/remdesk/server/remdesk_main.c @@ -152,7 +152,7 @@ static UINT remdesk_prepare_ctl_header(REMDESK_CTL_HEADER* ctlHeader, UINT32 msgType, UINT32 msgSize) { ctlHeader->msgType = msgType; - strcpy(ctlHeader->ChannelName, REMDESK_CHANNEL_CTL_NAME); + sprintf_s(ctlHeader->ChannelName, ARRAYSIZE(ctlHeader->ChannelName), REMDESK_CHANNEL_CTL_NAME); ctlHeader->DataLength = 4 + msgSize; return CHANNEL_RC_OK; } @@ -592,7 +592,6 @@ static DWORD WINAPI remdesk_server_thread(LPVOID arg) RemdeskServerContext* context; UINT error; context = (RemdeskServerContext*) arg; - buffer = NULL; BytesReturned = 0; ChannelEvent = NULL; @@ -727,7 +726,7 @@ static UINT remdesk_server_start(RemdeskServerContext* context) } if (!(context->priv->Thread = CreateThread(NULL, 0, - remdesk_server_thread, (void*) context, 0, NULL))) + remdesk_server_thread, (void*) context, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); CloseHandle(context->priv->StopEvent); @@ -790,7 +789,7 @@ void remdesk_server_context_free(RemdeskServerContext* context) { if (context->priv->ChannelHandle != INVALID_HANDLE_VALUE) WTSVirtualChannelClose(context->priv->ChannelHandle); - + free(context->priv); free(context); } diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index 28853c1..5d6286b 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -575,6 +575,8 @@ static void create_irp_thread(SERIAL_DEVICE* serial, IRP* irp) serial->IrpThreadToBeTerminatedCount); Sleep(1); /* 1 ms */ } + + free(ids); } LeaveCriticalSection(&serial->TerminatingIrpThreadsLock); @@ -694,6 +696,7 @@ static void terminate_pending_irp_threads(SERIAL_DEVICE* serial) } ListDictionary_Clear(serial->IrpThreads); + free(ids); } diff --git a/channels/server/channels.c b/channels/server/channels.c index 9f99ebb..8efff3f 100644 --- a/channels/server/channels.c +++ b/channels/server/channels.c @@ -51,37 +51,38 @@ #include #include -void freerdp_channels_dummy() +void freerdp_channels_dummy() { - audin_server_context_new(NULL); - audin_server_context_free(NULL); - - rdpsnd_server_context_new(NULL); - rdpsnd_server_context_free(NULL); - - cliprdr_server_context_new(NULL); - cliprdr_server_context_free(NULL); - - echo_server_context_new(NULL); - echo_server_context_free(NULL); - - rdpdr_server_context_new(NULL); - rdpdr_server_context_free(NULL); - - drdynvc_server_context_new(NULL); - drdynvc_server_context_free(NULL); - - rdpei_server_context_new(NULL); - rdpei_server_context_free(NULL); - - remdesk_server_context_new(NULL); - remdesk_server_context_free(NULL); - - encomsp_server_context_new(NULL); - encomsp_server_context_free(NULL); - - rdpgfx_server_context_new(NULL); - rdpgfx_server_context_free(NULL); + audin_server_context* audin; + RdpsndServerContext* rdpsnd; + CliprdrServerContext* cliprdr; + echo_server_context* echo; + RdpdrServerContext* rdpdr; + DrdynvcServerContext* drdynvc; + RdpeiServerContext* rdpei; + RemdeskServerContext* remdesk; + EncomspServerContext* encomsp; + RdpgfxServerContext* rdpgfx; + audin = audin_server_context_new(NULL); + audin_server_context_free(audin); + rdpsnd = rdpsnd_server_context_new(NULL); + rdpsnd_server_context_free(rdpsnd); + cliprdr = cliprdr_server_context_new(NULL); + cliprdr_server_context_free(cliprdr); + echo = echo_server_context_new(NULL); + echo_server_context_free(echo); + rdpdr = rdpdr_server_context_new(NULL); + rdpdr_server_context_free(rdpdr); + drdynvc = drdynvc_server_context_new(NULL); + drdynvc_server_context_free(drdynvc); + rdpei = rdpei_server_context_new(NULL); + rdpei_server_context_free(rdpei); + remdesk = remdesk_server_context_new(NULL); + remdesk_server_context_free(remdesk); + encomsp = encomsp_server_context_new(NULL); + encomsp_server_context_free(encomsp); + rdpgfx = rdpgfx_server_context_new(NULL); + rdpgfx_server_context_free(rdpgfx); } /** diff --git a/channels/smartcard/client/smartcard_main.c b/channels/smartcard/client/smartcard_main.c index 7046a70..134c021 100644 --- a/channels/smartcard/client/smartcard_main.c +++ b/channels/smartcard/client/smartcard_main.c @@ -34,6 +34,29 @@ #include "smartcard_main.h" +#define CAST_FROM_DEVICE(device) cast_device_from(device, __FUNCTION__, __FILE__, __LINE__) + +static SMARTCARD_DEVICE* sSmartcard = NULL; + +static SMARTCARD_DEVICE* cast_device_from(DEVICE* device, const char* fkt, const char* file, + int line) +{ + if (!device) + { + WLog_ERR(TAG, "%s [%s:%d] Called smartcard channel with NULL device", fkt, file, line); + return NULL; + } + + if (device->type != RDPDR_DTYP_SMARTCARD) + { + WLog_ERR(TAG, "%s [%s:%d] Called smartcard channel with invalid device of type %"PRIx32, + fkt, file, line, device->type); + return NULL; + } + + return (SMARTCARD_DEVICE*)device; +} + static DWORD WINAPI smartcard_context_thread(LPVOID arg) { SMARTCARD_CONTEXT* pContext = (SMARTCARD_CONTEXT*)arg; @@ -135,7 +158,7 @@ SMARTCARD_CONTEXT* smartcard_context_new(SMARTCARD_DEVICE* smartcard, } pContext->thread = CreateThread(NULL, 0, - smartcard_context_thread, + smartcard_context_thread, pContext, 0, NULL); if (!pContext->thread) @@ -152,8 +175,10 @@ error_irpqueue: return NULL; } -void smartcard_context_free(SMARTCARD_CONTEXT* pContext) +void smartcard_context_free(void* pCtx) { + SMARTCARD_CONTEXT* pContext = pCtx; + if (!pContext) return; @@ -169,7 +194,6 @@ void smartcard_context_free(SMARTCARD_CONTEXT* pContext) free(pContext); } - static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard) { int index; @@ -249,7 +273,29 @@ static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard) } } +static UINT smartcard_free_(SMARTCARD_DEVICE* smartcard) +{ + if (!smartcard) + return CHANNEL_RC_OK; + if (smartcard->IrpQueue) + { + MessageQueue_Free(smartcard->IrpQueue); + CloseHandle(smartcard->thread); + } + + Stream_Free(smartcard->device.data, TRUE); + LinkedList_Free(smartcard->names); + ListDictionary_Free(smartcard->rgSCardContextList); + ListDictionary_Free(smartcard->rgOutstandingMessages); + Queue_Free(smartcard->CompletedIrpQueue); + + if (smartcard->StartedEvent) + SCardReleaseStartedEvent(); + + free(smartcard); + return CHANNEL_RC_OK; +} /** * Function description * @@ -258,7 +304,11 @@ static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard) static UINT smartcard_free(DEVICE* device) { UINT error; - SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) device; + SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device); + + if (!smartcard) + return ERROR_INVALID_PARAMETER; + /** * Calling smartcard_release_all_contexts to unblock all operations waiting for transactions * to unlock. @@ -276,31 +326,12 @@ static UINT smartcard_free(DEVICE* device) WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); return error; } - - MessageQueue_Free(smartcard->IrpQueue); - smartcard->IrpQueue = NULL; - CloseHandle(smartcard->thread); - smartcard->thread = NULL; } - if (smartcard->device.data) - { - Stream_Free(smartcard->device.data, TRUE); - smartcard->device.data = NULL; - } + if (sSmartcard == smartcard) + sSmartcard = NULL; - ListDictionary_Free(smartcard->rgSCardContextList); - ListDictionary_Free(smartcard->rgOutstandingMessages); - Queue_Free(smartcard->CompletedIrpQueue); - - if (smartcard->StartedEvent) - { - SCardReleaseStartedEvent(); - smartcard->StartedEvent = NULL; - } - - free(device); - return CHANNEL_RC_OK; + return smartcard_free_(smartcard); } /** @@ -315,7 +346,11 @@ static UINT smartcard_free(DEVICE* device) */ static UINT smartcard_init(DEVICE* device) { - SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) device; + SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device); + + if (!smartcard) + return ERROR_INVALID_PARAMETER; + smartcard_release_all_contexts(smartcard); return CHANNEL_RC_OK; } @@ -325,7 +360,7 @@ static UINT smartcard_init(DEVICE* device) * * @return 0 on success, otherwise a Win32 error code */ -UINT smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) +static UINT smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) { void* key; key = (void*)(size_t) irp->CompletionId; @@ -343,7 +378,7 @@ UINT smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) * * @return 0 on success, otherwise a Win32 error code */ -UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) +static UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) { void* key; LONG status; @@ -377,10 +412,12 @@ UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*) irp)) { + free(operation); WLog_ERR(TAG, "Queue_Enqueue failed!"); return ERROR_INTERNAL_ERROR; } + free(operation); return CHANNEL_RC_OK; } @@ -460,6 +497,7 @@ UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*) irp)) { + free(operation); WLog_ERR(TAG, "Queue_Enqueue failed!"); return ERROR_INTERNAL_ERROR; } @@ -502,8 +540,12 @@ static DWORD WINAPI smartcard_thread_func(LPVOID arg) DWORD status; HANDLE hEvents[2]; wMessage message; - SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) arg; UINT error = CHANNEL_RC_OK; + SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(arg); + + if (!smartcard) + return ERROR_INVALID_PARAMETER; + nCount = 0; hEvents[nCount++] = MessageQueue_Event(smartcard->IrpQueue); hEvents[nCount++] = Queue_Event(smartcard->CompletedIrpQueue); @@ -657,7 +699,10 @@ out: */ static UINT smartcard_irp_request(DEVICE* device, IRP* irp) { - SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) device; + SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device); + + if (!smartcard) + return ERROR_INVALID_PARAMETER; if (!MessageQueue_Post(smartcard->IrpQueue, NULL, 0, (void*) irp, NULL)) { @@ -678,99 +723,101 @@ static UINT smartcard_irp_request(DEVICE* device, IRP* irp) */ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) { + SMARTCARD_DEVICE* smartcard = NULL; size_t length; - SMARTCARD_DEVICE* smartcard; UINT error = CHANNEL_RC_NO_MEMORY; - smartcard = (SMARTCARD_DEVICE*) calloc(1, sizeof(SMARTCARD_DEVICE)); - if (!smartcard) + if (!sSmartcard) { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; + wObject* obj; + smartcard = (SMARTCARD_DEVICE*) calloc(1, sizeof(SMARTCARD_DEVICE)); + + if (!smartcard) + { + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + smartcard->device.type = RDPDR_DTYP_SMARTCARD; + smartcard->device.name = "SCARD"; + smartcard->device.IRPRequest = smartcard_irp_request; + smartcard->device.Init = smartcard_init; + smartcard->device.Free = smartcard_free; + smartcard->names = LinkedList_New(); + smartcard->rdpcontext = pEntryPoints->rdpcontext; + length = strlen(smartcard->device.name); + smartcard->device.data = Stream_New(NULL, length + 1); + + if (!smartcard->device.data || !smartcard->names) + { + WLog_ERR(TAG, "Stream_New failed!"); + goto fail; + } + + Stream_Write(smartcard->device.data, "SCARD", 6); + smartcard->IrpQueue = MessageQueue_New(NULL); + + if (!smartcard->IrpQueue) + { + WLog_ERR(TAG, "MessageQueue_New failed!"); + goto fail; + } + + smartcard->CompletedIrpQueue = Queue_New(TRUE, -1, -1); + + if (!smartcard->CompletedIrpQueue) + { + WLog_ERR(TAG, "Queue_New failed!"); + goto fail; + } + + smartcard->rgSCardContextList = ListDictionary_New(TRUE); + + if (!smartcard->rgSCardContextList) + { + WLog_ERR(TAG, "ListDictionary_New failed!"); + goto fail; + } + + obj = ListDictionary_ValueObject(smartcard->rgSCardContextList); + obj->fnObjectFree = smartcard_context_free; + smartcard->rgOutstandingMessages = ListDictionary_New(TRUE); + + if (!smartcard->rgOutstandingMessages) + { + WLog_ERR(TAG, "ListDictionary_New failed!"); + goto fail; + } + + if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, &smartcard->device))) + { + WLog_ERR(TAG, "RegisterDevice failed!"); + goto fail; + } + + smartcard->thread = CreateThread(NULL, 0, + smartcard_thread_func, + smartcard, CREATE_SUSPENDED, NULL); + + if (!smartcard->thread) + { + WLog_ERR(TAG, "ListDictionary_New failed!"); + error = ERROR_INTERNAL_ERROR; + goto fail; + } + + ResumeThread(smartcard->thread); } + else + smartcard = sSmartcard; - smartcard->device.type = RDPDR_DTYP_SMARTCARD; - smartcard->device.name = "SCARD"; - smartcard->device.IRPRequest = smartcard_irp_request; - smartcard->device.Init = smartcard_init; - smartcard->device.Free = smartcard_free; - smartcard->rdpcontext = pEntryPoints->rdpcontext; - length = strlen(smartcard->device.name); - smartcard->device.data = Stream_New(NULL, length + 1); + if (pEntryPoints->device->Name) + LinkedList_AddLast(smartcard->names, pEntryPoints->device->Name); - if (!smartcard->device.data) - { - WLog_ERR(TAG, "Stream_New failed!"); - goto error_device_data; - } - - Stream_Write(smartcard->device.data, "SCARD", 6); - smartcard->IrpQueue = MessageQueue_New(NULL); - - if (!smartcard->IrpQueue) - { - WLog_ERR(TAG, "MessageQueue_New failed!"); - goto error_irp_queue; - } - - smartcard->CompletedIrpQueue = Queue_New(TRUE, -1, -1); - - if (!smartcard->CompletedIrpQueue) - { - WLog_ERR(TAG, "Queue_New failed!"); - goto error_completed_irp_queue; - } - - smartcard->rgSCardContextList = ListDictionary_New(TRUE); - - if (!smartcard->rgSCardContextList) - { - WLog_ERR(TAG, "ListDictionary_New failed!"); - goto error_context_list; - } - - ListDictionary_ValueObject(smartcard->rgSCardContextList)->fnObjectFree = - (OBJECT_FREE_FN) smartcard_context_free; - smartcard->rgOutstandingMessages = ListDictionary_New(TRUE); - - if (!smartcard->rgOutstandingMessages) - { - WLog_ERR(TAG, "ListDictionary_New failed!"); - goto error_outstanding_messages; - } - - if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, - (DEVICE*) smartcard))) - { - WLog_ERR(TAG, "RegisterDevice failed!"); - goto error_outstanding_messages; - } - - smartcard->thread = CreateThread(NULL, 0, - smartcard_thread_func, - smartcard, CREATE_SUSPENDED, NULL); - - if (!smartcard->thread) - { - WLog_ERR(TAG, "ListDictionary_New failed!"); - error = ERROR_INTERNAL_ERROR; - goto error_thread; - } - - ResumeThread(smartcard->thread); + sSmartcard = smartcard; return CHANNEL_RC_OK; -error_thread: - ListDictionary_Free(smartcard->rgOutstandingMessages); -error_outstanding_messages: - ListDictionary_Free(smartcard->rgSCardContextList); -error_context_list: - Queue_Free(smartcard->CompletedIrpQueue); -error_completed_irp_queue: - MessageQueue_Free(smartcard->IrpQueue); -error_irp_queue: - Stream_Free(smartcard->device.data, TRUE); -error_device_data: - free(smartcard); +fail: + smartcard_free_(smartcard); return error; } diff --git a/channels/smartcard/client/smartcard_main.h b/channels/smartcard/client/smartcard_main.h index 8451234..a867e69 100644 --- a/channels/smartcard/client/smartcard_main.h +++ b/channels/smartcard/client/smartcard_main.h @@ -117,15 +117,14 @@ struct _SMARTCARD_DEVICE wListDictionary* rgSCardContextList; wListDictionary* rgOutstandingMessages; rdpContext* rdpcontext; + wLinkedList* names; }; SMARTCARD_CONTEXT* smartcard_context_new(SMARTCARD_DEVICE* smartcard, SCARDCONTEXT hContext); -void smartcard_context_free(SMARTCARD_CONTEXT* pContext); +void smartcard_context_free(void* pContext); -UINT smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp); -UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp); - -LONG smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation); +LONG smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation); LONG smartcard_irp_device_control_call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation); #include "smartcard_pack.h" diff --git a/channels/smartcard/client/smartcard_operations.c b/channels/smartcard/client/smartcard_operations.c index 80dd4d0..4009b9f 100644 --- a/channels/smartcard/client/smartcard_operations.c +++ b/channels/smartcard/client/smartcard_operations.c @@ -432,6 +432,86 @@ static LONG smartcard_ListReaderGroupsW_Call(SMARTCARD_DEVICE* smartcard, return ret.ReturnCode; } +static BOOL filter_match(wLinkedList* list, LPCSTR reader, size_t readerLen) +{ + if (readerLen < 1) + return FALSE; + + LinkedList_Enumerator_Reset(list); + + while (LinkedList_Enumerator_MoveNext(list)) + { + const char* filter = LinkedList_Enumerator_Current(list); + + if (filter) + { + if (strstr(reader, filter) != NULL) + return TRUE; + } + } + + return FALSE; +} + +static DWORD filter_device_by_name_a(wLinkedList* list, LPSTR* mszReaders, DWORD cchReaders) +{ + size_t rpos = 0, wpos = 0; + + if (LinkedList_Count(list) < 1) + return cchReaders; + + do + { + LPCSTR rreader = &(*mszReaders)[rpos]; + LPSTR wreader = &(*mszReaders)[wpos]; + size_t readerLen = strnlen(rreader, cchReaders - rpos); + rpos += readerLen + 1; + + if (filter_match(list, rreader, readerLen)) + { + if (rreader != wreader) + memmove(wreader, rreader, readerLen); + + wpos += readerLen + 1; + } + } + while (rpos < cchReaders); + + /* this string must be double 0 terminated */ + if (rpos != wpos) + { + if (wpos >= cchReaders) + return 0; + + (*mszReaders)[wpos++] = '\0'; + } + + return wpos; +} + +static DWORD filter_device_by_name_w(wLinkedList* list, LPWSTR* mszReaders, DWORD cchReaders) +{ + DWORD rc; + LPSTR readers; + + if (LinkedList_Count(list) < 1) + return cchReaders; + + if (ConvertFromUnicode(CP_UTF8, 0, *mszReaders, (int)cchReaders, &readers, 0, NULL, + NULL) != cchReaders) + return 0; + + free(*mszReaders); + *mszReaders = NULL; + rc = filter_device_by_name_a(list, &readers, cchReaders); + + if (ConvertToUnicode(CP_UTF8, 0, readers, (int)rc, mszReaders, 0) != rc) + rc = 0; + + free(readers); + return rc; +} + static LONG smartcard_ListReadersA_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation) { @@ -462,6 +542,7 @@ static LONG smartcard_ListReadersA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_O cchReaders = SCARD_AUTOALLOCATE; status = ret.ReturnCode = SCardListReadersA(operation->hContext, (LPCSTR) call->mszGroups, (LPSTR) &mszReaders, &cchReaders); + cchReaders = filter_device_by_name_a(smartcard->names, &mszReaders, cchReaders); ret.msz = (BYTE*) mszReaders; ret.cBytes = cchReaders; @@ -524,6 +605,7 @@ static LONG smartcard_ListReadersW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_O cchReaders = SCARD_AUTOALLOCATE; status = ret.ReturnCode = SCardListReadersW(operation->hContext, (LPCWSTR) call->mszGroups, (LPWSTR) &mszReaders, &cchReaders); + cchReaders = filter_device_by_name_w(smartcard->names, &mszReaders, cchReaders); ret.msz = (BYTE*) mszReaders; ret.cBytes = cchReaders * 2; @@ -1053,7 +1135,6 @@ static LONG smartcard_StatusA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERAT IRP* irp = operation->irp; Status_Call* call = operation->call; ZeroMemory(ret.pbAtr, 32); - call->cbAtrLen = 32; cbAtrLen = call->cbAtrLen; @@ -1142,7 +1223,13 @@ static LONG smartcard_StatusW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERAT if (!call->fmszReaderNamesIsNULL) ret.mszReaderNames = (BYTE*) mszReaderNames; + // WinScard returns the number of CHARACTERS whereas pcsc-lite returns the + // number of BYTES. +#ifdef _WIN32 + ret.cBytes = cchReaderLen * 2; +#else ret.cBytes = cchReaderLen; +#endif if (call->cbAtrLen) ret.cbAtrLen = cbAtrLen; diff --git a/channels/sshagent/server/sshagent_main.c b/channels/sshagent/server/sshagent_main.c index 3bbd6d5..dce713c 100644 --- a/channels/sshagent/server/sshagent_main.c +++ b/channels/sshagent/server/sshagent_main.c @@ -110,8 +110,8 @@ #define _PATH_DEVNULL "/dev/null" -char socket_name[PATH_MAX]; -char socket_dir[PATH_MAX]; +static char socket_name[PATH_MAX]; +static char socket_dir[PATH_MAX]; static int sa_uds_fd = -1; static int is_going = 1; @@ -156,7 +156,7 @@ setup_ssh_agent(struct sockaddr_un* addr) exit(1); } - snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir, + snprintf(socket_name, sizeof(socket_name), "%s/agent.%ld", socket_dir, (long)getpid()); /* Create unix domain socket */ unlink(socket_name); diff --git a/channels/tsmf/client/alsa/tsmf_alsa.c b/channels/tsmf/client/alsa/tsmf_alsa.c index 78a0a66..3cf821b 100644 --- a/channels/tsmf/client/alsa/tsmf_alsa.c +++ b/channels/tsmf/client/alsa/tsmf_alsa.c @@ -40,33 +40,34 @@ typedef struct _TSMFALSAAudioDevice ITSMFAudioDevice iface; char device[32]; - snd_pcm_t *out_handle; + snd_pcm_t* out_handle; UINT32 source_rate; UINT32 actual_rate; UINT32 source_channels; UINT32 actual_channels; UINT32 bytes_per_sample; - - FREERDP_DSP_CONTEXT *dsp_context; } TSMFAlsaAudioDevice; -static BOOL tsmf_alsa_open_device(TSMFAlsaAudioDevice *alsa) +static BOOL tsmf_alsa_open_device(TSMFAlsaAudioDevice* alsa) { int error; error = snd_pcm_open(&alsa->out_handle, alsa->device, SND_PCM_STREAM_PLAYBACK, 0); - if(error < 0) + + if (error < 0) { WLog_ERR(TAG, "failed to open device %s", alsa->device); return FALSE; } + DEBUG_TSMF("open device %s", alsa->device); return TRUE; } -static BOOL tsmf_alsa_open(ITSMFAudioDevice *audio, const char *device) +static BOOL tsmf_alsa_open(ITSMFAudioDevice* audio, const char* device) { - TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio; - if(!device) + TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio; + + if (!device) { strncpy(alsa->device, "default", sizeof(alsa->device)); } @@ -74,114 +75,109 @@ static BOOL tsmf_alsa_open(ITSMFAudioDevice *audio, const char *device) { strncpy(alsa->device, device, sizeof(alsa->device) - 1); } + return tsmf_alsa_open_device(alsa); } -static BOOL tsmf_alsa_set_format(ITSMFAudioDevice *audio, - UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample) +static BOOL tsmf_alsa_set_format(ITSMFAudioDevice* audio, + UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample) { int error; snd_pcm_uframes_t frames; - snd_pcm_hw_params_t *hw_params; - snd_pcm_sw_params_t *sw_params; - TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio; - if(!alsa->out_handle) + snd_pcm_hw_params_t* hw_params; + snd_pcm_sw_params_t* sw_params; + TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio; + + if (!alsa->out_handle) return FALSE; + snd_pcm_drop(alsa->out_handle); alsa->actual_rate = alsa->source_rate = sample_rate; alsa->actual_channels = alsa->source_channels = channels; alsa->bytes_per_sample = bits_per_sample / 8; error = snd_pcm_hw_params_malloc(&hw_params); - if(error < 0) + + if (error < 0) { WLog_ERR(TAG, "snd_pcm_hw_params_malloc failed"); return FALSE; } + snd_pcm_hw_params_any(alsa->out_handle, hw_params); snd_pcm_hw_params_set_access(alsa->out_handle, hw_params, - SND_PCM_ACCESS_RW_INTERLEAVED); + SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_format(alsa->out_handle, hw_params, - SND_PCM_FORMAT_S16_LE); + SND_PCM_FORMAT_S16_LE); snd_pcm_hw_params_set_rate_near(alsa->out_handle, hw_params, - &alsa->actual_rate, NULL); + &alsa->actual_rate, NULL); snd_pcm_hw_params_set_channels_near(alsa->out_handle, hw_params, - &alsa->actual_channels); + &alsa->actual_channels); frames = sample_rate; snd_pcm_hw_params_set_buffer_size_near(alsa->out_handle, hw_params, - &frames); + &frames); snd_pcm_hw_params(alsa->out_handle, hw_params); snd_pcm_hw_params_free(hw_params); error = snd_pcm_sw_params_malloc(&sw_params); - if(error < 0) + + if (error < 0) { WLog_ERR(TAG, "snd_pcm_sw_params_malloc"); return FALSE; } + snd_pcm_sw_params_current(alsa->out_handle, sw_params); snd_pcm_sw_params_set_start_threshold(alsa->out_handle, sw_params, - frames / 2); + frames / 2); snd_pcm_sw_params(alsa->out_handle, sw_params); snd_pcm_sw_params_free(sw_params); snd_pcm_prepare(alsa->out_handle); DEBUG_TSMF("sample_rate %"PRIu32" channels %"PRIu32" bits_per_sample %"PRIu32"", - sample_rate, channels, bits_per_sample); + sample_rate, channels, bits_per_sample); DEBUG_TSMF("hardware buffer %lu frames", frames); - if((alsa->actual_rate != alsa->source_rate) || - (alsa->actual_channels != alsa->source_channels)) + + if ((alsa->actual_rate != alsa->source_rate) || + (alsa->actual_channels != alsa->source_channels)) { DEBUG_TSMF("actual rate %"PRIu32" / channel %"PRIu32" is different " "from source rate %"PRIu32" / channel %"PRIu32", resampling required.", - alsa->actual_rate, alsa->actual_channels, - alsa->source_rate, alsa->source_channels); + alsa->actual_rate, alsa->actual_channels, + alsa->source_rate, alsa->source_channels); } + return TRUE; } -static BOOL tsmf_alsa_play(ITSMFAudioDevice *audio, BYTE *data, UINT32 data_size) +static BOOL tsmf_alsa_play(ITSMFAudioDevice* audio, const BYTE* src, UINT32 data_size) { int len; int error; int frames; - BYTE *end; - BYTE *src; - BYTE *pindex; + const BYTE* end; + const BYTE* pindex; int rbytes_per_frame; int sbytes_per_frame; - TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio; + TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio; DEBUG_TSMF("data_size %"PRIu32"", data_size); - if(alsa->out_handle) + + if (alsa->out_handle) { sbytes_per_frame = alsa->source_channels * alsa->bytes_per_sample; rbytes_per_frame = alsa->actual_channels * alsa->bytes_per_sample; - if((alsa->source_rate == alsa->actual_rate) && - (alsa->source_channels == alsa->actual_channels)) - { - src = data; - } - else - { - alsa->dsp_context->resample(alsa->dsp_context, data, alsa->bytes_per_sample, - alsa->source_channels, alsa->source_rate, data_size / sbytes_per_frame, - alsa->actual_channels, alsa->actual_rate); - frames = alsa->dsp_context->resampled_frames; - DEBUG_TSMF("resampled %"PRIu32" frames at %"PRIu32" to %d frames at %"PRIu32"", - data_size / sbytes_per_frame, alsa->source_rate, frames, alsa->actual_rate); - data_size = frames * rbytes_per_frame; - src = alsa->dsp_context->resampled_buffer; - } pindex = src; end = pindex + data_size; - while(pindex < end) + + while (pindex < end) { len = end - pindex; frames = len / rbytes_per_frame; error = snd_pcm_writei(alsa->out_handle, pindex, frames); - if(error == -EPIPE) + + if (error == -EPIPE) { snd_pcm_recover(alsa->out_handle, error, 0); error = 0; } - else if(error < 0) + else if (error < 0) { DEBUG_TSMF("error len %d", error); snd_pcm_close(alsa->out_handle); @@ -189,45 +185,51 @@ static BOOL tsmf_alsa_play(ITSMFAudioDevice *audio, BYTE *data, UINT32 data_size tsmf_alsa_open_device(alsa); break; } + DEBUG_TSMF("%d frames played.", error); - if(error == 0) + + if (error == 0) break; + pindex += error * rbytes_per_frame; } } - free(data); + return TRUE; } -static UINT64 tsmf_alsa_get_latency(ITSMFAudioDevice *audio) +static UINT64 tsmf_alsa_get_latency(ITSMFAudioDevice* audio) { UINT64 latency = 0; snd_pcm_sframes_t frames = 0; - TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio; - if(alsa->out_handle && alsa->actual_rate > 0 && - snd_pcm_delay(alsa->out_handle, &frames) == 0 && - frames > 0) + TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio; + + if (alsa->out_handle && alsa->actual_rate > 0 && + snd_pcm_delay(alsa->out_handle, &frames) == 0 && + frames > 0) { latency = ((UINT64)frames) * 10000000LL / (UINT64) alsa->actual_rate; } + return latency; } -static BOOL tsmf_alsa_flush(ITSMFAudioDevice *audio) +static BOOL tsmf_alsa_flush(ITSMFAudioDevice* audio) { return TRUE; } -static void tsmf_alsa_free(ITSMFAudioDevice *audio) +static void tsmf_alsa_free(ITSMFAudioDevice* audio) { - TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio; + TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio; DEBUG_TSMF(""); - if(alsa->out_handle) + + if (alsa->out_handle) { snd_pcm_drain(alsa->out_handle); snd_pcm_close(alsa->out_handle); } - freerdp_dsp_context_free(alsa->dsp_context); + free(alsa); } @@ -237,10 +239,10 @@ static void tsmf_alsa_free(ITSMFAudioDevice *audio) #define freerdp_tsmf_client_audio_subsystem_entry FREERDP_API freerdp_tsmf_client_audio_subsystem_entry #endif -ITSMFAudioDevice *freerdp_tsmf_client_audio_subsystem_entry(void) +ITSMFAudioDevice* freerdp_tsmf_client_audio_subsystem_entry(void) { - TSMFAlsaAudioDevice *alsa; - alsa = (TSMFAlsaAudioDevice *) malloc(sizeof(TSMFAlsaAudioDevice)); + TSMFAlsaAudioDevice* alsa; + alsa = (TSMFAlsaAudioDevice*) malloc(sizeof(TSMFAlsaAudioDevice)); ZeroMemory(alsa, sizeof(TSMFAlsaAudioDevice)); alsa->iface.Open = tsmf_alsa_open; alsa->iface.SetFormat = tsmf_alsa_set_format; @@ -248,6 +250,5 @@ ITSMFAudioDevice *freerdp_tsmf_client_audio_subsystem_entry(void) alsa->iface.GetLatency = tsmf_alsa_get_latency; alsa->iface.Flush = tsmf_alsa_flush; alsa->iface.Free = tsmf_alsa_free; - alsa->dsp_context = freerdp_dsp_context_new(); - return (ITSMFAudioDevice *) alsa; + return (ITSMFAudioDevice*) alsa; } diff --git a/channels/tsmf/client/oss/tsmf_oss.c b/channels/tsmf/client/oss/tsmf_oss.c index db88ddb..67a7927 100644 --- a/channels/tsmf/client/oss/tsmf_oss.c +++ b/channels/tsmf/client/oss/tsmf_oss.c @@ -35,9 +35,9 @@ #include #include #if defined(__OpenBSD__) - #include +#include #else - #include +#include #endif #include @@ -129,7 +129,8 @@ static BOOL tsmf_oss_open(ITSMFAudioDevice* audio, const char* device) return TRUE; } -static BOOL tsmf_oss_set_format(ITSMFAudioDevice* audio, UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample) +static BOOL tsmf_oss_set_format(ITSMFAudioDevice* audio, UINT32 sample_rate, UINT32 channels, + UINT32 bits_per_sample) { int tmp; TSMFOssAudioDevice* oss = (TSMFOssAudioDevice*)audio; @@ -161,11 +162,11 @@ static BOOL tsmf_oss_set_format(ITSMFAudioDevice* audio, UINT32 sample_rate, UIN OSS_LOG_ERR("SNDCTL_DSP_SETFRAGMENT failed", errno); DEBUG_TSMF("sample_rate %"PRIu32" channels %"PRIu32" bits_per_sample %"PRIu32"", - sample_rate, channels, bits_per_sample); + sample_rate, channels, bits_per_sample); return TRUE; } -static BOOL tsmf_oss_play(ITSMFAudioDevice* audio, BYTE* data, UINT32 data_size) +static BOOL tsmf_oss_play(ITSMFAudioDevice* audio, const BYTE* data, UINT32 data_size) { int status; UINT32 offset; @@ -176,10 +177,7 @@ static BOOL tsmf_oss_play(ITSMFAudioDevice* audio, BYTE* data, UINT32 data_size) return FALSE; if (data == NULL || data_size == 0) - { - free(data); return TRUE; - } offset = 0; oss->data_size_last = data_size; @@ -191,14 +189,12 @@ static BOOL tsmf_oss_play(ITSMFAudioDevice* audio, BYTE* data, UINT32 data_size) if (status < 0) { OSS_LOG_ERR("write fail", errno); - free(data); return FALSE; } offset += status; } - free(data); return TRUE; } diff --git a/channels/tsmf/client/pulse/tsmf_pulse.c b/channels/tsmf/client/pulse/tsmf_pulse.c index e6da925..e63477c 100644 --- a/channels/tsmf/client/pulse/tsmf_pulse.c +++ b/channels/tsmf/client/pulse/tsmf_pulse.c @@ -37,68 +37,81 @@ typedef struct _TSMFPulseAudioDevice ITSMFAudioDevice iface; char device[32]; - pa_threaded_mainloop *mainloop; - pa_context *context; + pa_threaded_mainloop* mainloop; + pa_context* context; pa_sample_spec sample_spec; - pa_stream *stream; + pa_stream* stream; } TSMFPulseAudioDevice; -static void tsmf_pulse_context_state_callback(pa_context *context, void *userdata) +static void tsmf_pulse_context_state_callback(pa_context* context, void* userdata) { - TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) userdata; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata; pa_context_state_t state; state = pa_context_get_state(context); - switch(state) + + switch (state) { case PA_CONTEXT_READY: DEBUG_TSMF("PA_CONTEXT_READY"); pa_threaded_mainloop_signal(pulse->mainloop, 0); break; + case PA_CONTEXT_FAILED: case PA_CONTEXT_TERMINATED: DEBUG_TSMF("state %d", state); pa_threaded_mainloop_signal(pulse->mainloop, 0); break; + default: DEBUG_TSMF("state %d", state); break; } } -static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice *pulse) +static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice* pulse) { pa_context_state_t state; - if(!pulse->context) + + if (!pulse->context) return FALSE; - if(pa_context_connect(pulse->context, NULL, 0, NULL)) + + if (pa_context_connect(pulse->context, NULL, 0, NULL)) { WLog_ERR(TAG, "pa_context_connect failed (%d)", - pa_context_errno(pulse->context)); + pa_context_errno(pulse->context)); return FALSE; } + pa_threaded_mainloop_lock(pulse->mainloop); - if(pa_threaded_mainloop_start(pulse->mainloop) < 0) + + if (pa_threaded_mainloop_start(pulse->mainloop) < 0) { pa_threaded_mainloop_unlock(pulse->mainloop); WLog_ERR(TAG, "pa_threaded_mainloop_start failed (%d)", - pa_context_errno(pulse->context)); + pa_context_errno(pulse->context)); return FALSE; } - for(;;) + + for (;;) { state = pa_context_get_state(pulse->context); - if(state == PA_CONTEXT_READY) + + if (state == PA_CONTEXT_READY) break; - if(!PA_CONTEXT_IS_GOOD(state)) + + if (!PA_CONTEXT_IS_GOOD(state)) { DEBUG_TSMF("bad context state (%d)", - pa_context_errno(pulse->context)); + pa_context_errno(pulse->context)); break; } + pa_threaded_mainloop_wait(pulse->mainloop); } + pa_threaded_mainloop_unlock(pulse->mainloop); - if(state == PA_CONTEXT_READY) + + if (state == PA_CONTEXT_READY) { DEBUG_TSMF("connected"); return TRUE; @@ -110,90 +123,104 @@ static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice *pulse) } } -static BOOL tsmf_pulse_open(ITSMFAudioDevice *audio, const char *device) +static BOOL tsmf_pulse_open(ITSMFAudioDevice* audio, const char* device) { - TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio; - if(device) + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; + + if (device) { strncpy(pulse->device, device, sizeof(pulse->device) - 1); } + pulse->mainloop = pa_threaded_mainloop_new(); - if(!pulse->mainloop) + + if (!pulse->mainloop) { WLog_ERR(TAG, "pa_threaded_mainloop_new failed"); return FALSE; } + pulse->context = pa_context_new(pa_threaded_mainloop_get_api(pulse->mainloop), "freerdp"); - if(!pulse->context) + + if (!pulse->context) { WLog_ERR(TAG, "pa_context_new failed"); return FALSE; } + pa_context_set_state_callback(pulse->context, tsmf_pulse_context_state_callback, pulse); - if(!tsmf_pulse_connect(pulse)) + + if (!tsmf_pulse_connect(pulse)) { WLog_ERR(TAG, "tsmf_pulse_connect failed"); return FALSE; } + DEBUG_TSMF("open device %s", pulse->device); return TRUE; } -static void tsmf_pulse_stream_success_callback(pa_stream *stream, int success, void *userdata) +static void tsmf_pulse_stream_success_callback(pa_stream* stream, int success, void* userdata) { - TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) userdata; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata; pa_threaded_mainloop_signal(pulse->mainloop, 0); } -static void tsmf_pulse_wait_for_operation(TSMFPulseAudioDevice *pulse, pa_operation *operation) +static void tsmf_pulse_wait_for_operation(TSMFPulseAudioDevice* pulse, pa_operation* operation) { - if(operation == NULL) + if (operation == NULL) return; - while(pa_operation_get_state(operation) == PA_OPERATION_RUNNING) + + while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) { pa_threaded_mainloop_wait(pulse->mainloop); } + pa_operation_unref(operation); } -static void tsmf_pulse_stream_state_callback(pa_stream *stream, void *userdata) +static void tsmf_pulse_stream_state_callback(pa_stream* stream, void* userdata) { - TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) userdata; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata; pa_stream_state_t state; state = pa_stream_get_state(stream); - switch(state) + + switch (state) { case PA_STREAM_READY: DEBUG_TSMF("PA_STREAM_READY"); pa_threaded_mainloop_signal(pulse->mainloop, 0); break; + case PA_STREAM_FAILED: case PA_STREAM_TERMINATED: DEBUG_TSMF("state %d", state); pa_threaded_mainloop_signal(pulse->mainloop, 0); break; + default: DEBUG_TSMF("state %d", state); break; } } -static void tsmf_pulse_stream_request_callback(pa_stream *stream, size_t length, void *userdata) +static void tsmf_pulse_stream_request_callback(pa_stream* stream, size_t length, void* userdata) { - TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) userdata; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata; DEBUG_TSMF("%"PRIdz"", length); pa_threaded_mainloop_signal(pulse->mainloop, 0); } -static BOOL tsmf_pulse_close_stream(TSMFPulseAudioDevice *pulse) +static BOOL tsmf_pulse_close_stream(TSMFPulseAudioDevice* pulse) { - if(!pulse->context || !pulse->stream) + if (!pulse->context || !pulse->stream) return FALSE; + DEBUG_TSMF(""); pa_threaded_mainloop_lock(pulse->mainloop); pa_stream_set_write_callback(pulse->stream, NULL, NULL); tsmf_pulse_wait_for_operation(pulse, - pa_stream_drain(pulse->stream, tsmf_pulse_stream_success_callback, pulse)); + pa_stream_drain(pulse->stream, tsmf_pulse_stream_success_callback, pulse)); pa_stream_disconnect(pulse->stream); pa_stream_unref(pulse->stream); pulse->stream = NULL; @@ -201,57 +228,68 @@ static BOOL tsmf_pulse_close_stream(TSMFPulseAudioDevice *pulse) return TRUE; } -static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice *pulse) +static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice* pulse) { pa_stream_state_t state; pa_buffer_attr buffer_attr = { 0 }; - if(!pulse->context) + + if (!pulse->context) return FALSE; + DEBUG_TSMF(""); pa_threaded_mainloop_lock(pulse->mainloop); pulse->stream = pa_stream_new(pulse->context, "freerdp", - &pulse->sample_spec, NULL); - if(!pulse->stream) + &pulse->sample_spec, NULL); + + if (!pulse->stream) { pa_threaded_mainloop_unlock(pulse->mainloop); WLog_ERR(TAG, "pa_stream_new failed (%d)", - pa_context_errno(pulse->context)); + pa_context_errno(pulse->context)); return FALSE; } + pa_stream_set_state_callback(pulse->stream, - tsmf_pulse_stream_state_callback, pulse); + tsmf_pulse_stream_state_callback, pulse); pa_stream_set_write_callback(pulse->stream, - tsmf_pulse_stream_request_callback, pulse); + tsmf_pulse_stream_request_callback, pulse); buffer_attr.maxlength = pa_usec_to_bytes(500000, &pulse->sample_spec); buffer_attr.tlength = pa_usec_to_bytes(250000, &pulse->sample_spec); - buffer_attr.prebuf = (UINT32) -1; - buffer_attr.minreq = (UINT32) -1; - buffer_attr.fragsize = (UINT32) -1; - if(pa_stream_connect_playback(pulse->stream, - pulse->device[0] ? pulse->device : NULL, &buffer_attr, - PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE, - NULL, NULL) < 0) + buffer_attr.prebuf = (UINT32) - 1; + buffer_attr.minreq = (UINT32) - 1; + buffer_attr.fragsize = (UINT32) - 1; + + if (pa_stream_connect_playback(pulse->stream, + pulse->device[0] ? pulse->device : NULL, &buffer_attr, + PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE, + NULL, NULL) < 0) { pa_threaded_mainloop_unlock(pulse->mainloop); WLog_ERR(TAG, "pa_stream_connect_playback failed (%d)", - pa_context_errno(pulse->context)); + pa_context_errno(pulse->context)); return FALSE; } - for(;;) + + for (;;) { state = pa_stream_get_state(pulse->stream); - if(state == PA_STREAM_READY) + + if (state == PA_STREAM_READY) break; - if(!PA_STREAM_IS_GOOD(state)) + + if (!PA_STREAM_IS_GOOD(state)) { WLog_ERR(TAG, "bad stream state (%d)", - pa_context_errno(pulse->context)); + pa_context_errno(pulse->context)); break; } + pa_threaded_mainloop_wait(pulse->mainloop); } + pa_threaded_mainloop_unlock(pulse->mainloop); - if(state == PA_STREAM_READY) + + if (state == PA_STREAM_READY) { DEBUG_TSMF("connected"); return TRUE; @@ -263,118 +301,133 @@ static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice *pulse) } } -static BOOL tsmf_pulse_set_format(ITSMFAudioDevice *audio, - UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample) +static BOOL tsmf_pulse_set_format(ITSMFAudioDevice* audio, + UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample) { - TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; DEBUG_TSMF("sample_rate %"PRIu32" channels %"PRIu32" bits_per_sample %"PRIu32"", - sample_rate, channels, bits_per_sample); + sample_rate, channels, bits_per_sample); pulse->sample_spec.rate = sample_rate; pulse->sample_spec.channels = channels; pulse->sample_spec.format = PA_SAMPLE_S16LE; return tsmf_pulse_open_stream(pulse); } -static BOOL tsmf_pulse_play(ITSMFAudioDevice *audio, BYTE *data, UINT32 data_size) +static BOOL tsmf_pulse_play(ITSMFAudioDevice* audio, const BYTE* data, UINT32 data_size) { - TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio; - BYTE *src; - int len; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; + const BYTE* src; + size_t len; int ret; DEBUG_TSMF("data_size %"PRIu32"", data_size); - if(pulse->stream) + + if (pulse->stream) { pa_threaded_mainloop_lock(pulse->mainloop); src = data; - while(data_size > 0) + + while (data_size > 0) { - while((len = pa_stream_writable_size(pulse->stream)) == 0) + while ((len = pa_stream_writable_size(pulse->stream)) == 0) { DEBUG_TSMF("waiting"); pa_threaded_mainloop_wait(pulse->mainloop); } - if(len < 0) + + if (len == (size_t) -1) break; - if(len > data_size) + + if (len > data_size) len = data_size; + ret = pa_stream_write(pulse->stream, src, len, NULL, 0LL, PA_SEEK_RELATIVE); - if(ret < 0) + + if (ret < 0) { DEBUG_TSMF("pa_stream_write failed (%d)", - pa_context_errno(pulse->context)); + pa_context_errno(pulse->context)); break; } + src += len; data_size -= len; } + pa_threaded_mainloop_unlock(pulse->mainloop); } - free(data); + return TRUE; } -static UINT64 tsmf_pulse_get_latency(ITSMFAudioDevice *audio) +static UINT64 tsmf_pulse_get_latency(ITSMFAudioDevice* audio) { pa_usec_t usec; UINT64 latency = 0; - TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio; - if(pulse->stream && pa_stream_get_latency(pulse->stream, &usec, NULL) == 0) + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; + + if (pulse->stream && pa_stream_get_latency(pulse->stream, &usec, NULL) == 0) { latency = ((UINT64)usec) * 10LL; } + return latency; } -static BOOL tsmf_pulse_flush(ITSMFAudioDevice *audio) +static BOOL tsmf_pulse_flush(ITSMFAudioDevice* audio) { - TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; pa_threaded_mainloop_lock(pulse->mainloop); tsmf_pulse_wait_for_operation(pulse, - pa_stream_flush(pulse->stream, tsmf_pulse_stream_success_callback, pulse)); + pa_stream_flush(pulse->stream, tsmf_pulse_stream_success_callback, pulse)); pa_threaded_mainloop_unlock(pulse->mainloop); return TRUE; } -static void tsmf_pulse_free(ITSMFAudioDevice *audio) +static void tsmf_pulse_free(ITSMFAudioDevice* audio) { - TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; DEBUG_TSMF(""); tsmf_pulse_close_stream(pulse); - if(pulse->mainloop) + + if (pulse->mainloop) { pa_threaded_mainloop_stop(pulse->mainloop); } - if(pulse->context) + + if (pulse->context) { pa_context_disconnect(pulse->context); pa_context_unref(pulse->context); pulse->context = NULL; } - if(pulse->mainloop) + + if (pulse->mainloop) { pa_threaded_mainloop_free(pulse->mainloop); pulse->mainloop = NULL; } + free(pulse); } #ifdef BUILTIN_CHANNELS -ITSMFAudioDevice *pulse_freerdp_tsmf_client_audio_subsystem_entry(void) +ITSMFAudioDevice* pulse_freerdp_tsmf_client_audio_subsystem_entry(void) #else -FREERDP_API ITSMFAudioDevice *freerdp_tsmf_client_audio_subsystem_entry(void) +FREERDP_API ITSMFAudioDevice* freerdp_tsmf_client_audio_subsystem_entry(void) #endif { - TSMFPulseAudioDevice *pulse; + TSMFPulseAudioDevice* pulse; + pulse = (TSMFPulseAudioDevice*) calloc(1, sizeof(TSMFPulseAudioDevice)); - pulse = (TSMFPulseAudioDevice *) calloc(1, sizeof(TSMFPulseAudioDevice)); if (!pulse) return NULL; + pulse->iface.Open = tsmf_pulse_open; pulse->iface.SetFormat = tsmf_pulse_set_format; pulse->iface.Play = tsmf_pulse_play; pulse->iface.GetLatency = tsmf_pulse_get_latency; pulse->iface.Flush = tsmf_pulse_flush; pulse->iface.Free = tsmf_pulse_free; - return (ITSMFAudioDevice *) pulse; + return (ITSMFAudioDevice*) pulse; } diff --git a/channels/tsmf/client/tsmf_audio.h b/channels/tsmf/client/tsmf_audio.h index a8c7a49..d589d54 100644 --- a/channels/tsmf/client/tsmf_audio.h +++ b/channels/tsmf/client/tsmf_audio.h @@ -27,23 +27,24 @@ typedef struct _ITSMFAudioDevice ITSMFAudioDevice; struct _ITSMFAudioDevice { /* Open the audio device. */ - BOOL (*Open) (ITSMFAudioDevice* audio, const char* device); + BOOL (*Open)(ITSMFAudioDevice* audio, const char* device); /* Set the audio data format. */ - BOOL (*SetFormat) (ITSMFAudioDevice* audio, UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample); + BOOL (*SetFormat)(ITSMFAudioDevice* audio, UINT32 sample_rate, UINT32 channels, + UINT32 bits_per_sample); /* Play audio data. */ - BOOL (*Play) (ITSMFAudioDevice* audio, BYTE* data, UINT32 data_size); + BOOL (*Play)(ITSMFAudioDevice* audio, const BYTE* data, UINT32 data_size); /* Get the latency of the last written sample, in 100ns */ - UINT64 (*GetLatency) (ITSMFAudioDevice* audio); + UINT64(*GetLatency)(ITSMFAudioDevice* audio); /* Change the playback volume level */ - BOOL (*ChangeVolume) (ITSMFAudioDevice* audio, UINT32 newVolume, UINT32 muted); + BOOL (*ChangeVolume)(ITSMFAudioDevice* audio, UINT32 newVolume, UINT32 muted); /* Flush queued audio data */ - BOOL (*Flush) (ITSMFAudioDevice* audio); + BOOL (*Flush)(ITSMFAudioDevice* audio); /* Free the audio device */ - void (*Free) (ITSMFAudioDevice* audio); + void (*Free)(ITSMFAudioDevice* audio); }; #define TSMF_AUDIO_DEVICE_EXPORT_FUNC_NAME "TSMFAudioDeviceEntry" -typedef ITSMFAudioDevice* (*TSMF_AUDIO_DEVICE_ENTRY) (void); +typedef ITSMFAudioDevice* (*TSMF_AUDIO_DEVICE_ENTRY)(void); ITSMFAudioDevice* tsmf_load_audio_device(const char* name, const char* device); diff --git a/channels/tsmf/client/tsmf_main.c b/channels/tsmf/client/tsmf_main.c index a6339be..9309235 100644 --- a/channels/tsmf/client/tsmf_main.c +++ b/channels/tsmf/client/tsmf_main.c @@ -51,8 +51,10 @@ BOOL tsmf_send_eos_response(IWTSVirtualChannelCallback* pChannelCallback, UINT32 if (callback && callback->stream_id && callback->channel && callback->channel->Write) { s = Stream_New(NULL, 24); + if (!s) return FALSE; + Stream_Write_UINT32(s, TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY); Stream_Write_UINT32(s, message_id); Stream_Write_UINT32(s, CLIENT_EVENT_NOTIFICATION); /* FunctionId */ @@ -60,29 +62,31 @@ BOOL tsmf_send_eos_response(IWTSVirtualChannelCallback* pChannelCallback, UINT32 Stream_Write_UINT32(s, TSMM_CLIENT_EVENT_ENDOFSTREAM); /* EventId */ Stream_Write_UINT32(s, 0); /* cbData */ DEBUG_TSMF("EOS response size %"PRIuz"", Stream_GetPosition(s)); - status = callback->channel->Write(callback->channel, Stream_GetPosition(s), Stream_Buffer(s), NULL); + if (status) { WLog_ERR(TAG, "response error %d", status); } + Stream_Free(s, TRUE); } return (status == 0); } -BOOL tsmf_playback_ack(IWTSVirtualChannelCallback *pChannelCallback, - UINT32 message_id, UINT64 duration, UINT32 data_size) +BOOL tsmf_playback_ack(IWTSVirtualChannelCallback* pChannelCallback, + UINT32 message_id, UINT64 duration, UINT32 data_size) { - wStream *s = NULL; + wStream* s = NULL; int status = -1; - TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback; + TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback; - if (!callback) + if (!callback) return FALSE; s = Stream_New(NULL, 32); + if (!s) return FALSE; @@ -92,7 +96,6 @@ BOOL tsmf_playback_ack(IWTSVirtualChannelCallback *pChannelCallback, Stream_Write_UINT32(s, callback->stream_id); /* StreamId */ Stream_Write_UINT64(s, duration); /* DataDuration */ Stream_Write_UINT64(s, data_size); /* cbData */ - DEBUG_TSMF("ACK response size %"PRIuz"", Stream_GetPosition(s)); if (!callback->channel || !callback->channel->Write) @@ -104,7 +107,7 @@ BOOL tsmf_playback_ack(IWTSVirtualChannelCallback *pChannelCallback, else { status = callback->channel->Write(callback->channel, - Stream_GetPosition(s), Stream_Buffer(s), NULL); + Stream_GetPosition(s), Stream_Buffer(s), NULL); } if (status) @@ -121,11 +124,11 @@ BOOL tsmf_playback_ack(IWTSVirtualChannelCallback *pChannelCallback, * * @return 0 on success, otherwise a Win32 error code */ -static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data) +static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data) { size_t length; - wStream *input; - wStream *output; + wStream* input; + wStream* output; UINT error = CHANNEL_RC_OK; BOOL processed = FALSE; TSMF_IFMAN ifman; @@ -144,16 +147,16 @@ static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, input = data; output = Stream_New(NULL, 256); + if (!output) return ERROR_OUTOFMEMORY; + Stream_Seek(output, 8); Stream_Read_UINT32(input, InterfaceId); /* InterfaceId (4 bytes) */ Stream_Read_UINT32(input, MessageId); /* MessageId (4 bytes) */ Stream_Read_UINT32(input, FunctionId); /* FunctionId (4 bytes) */ - DEBUG_TSMF("cbSize=%"PRIu32" InterfaceId=0x%"PRIX32" MessageId=0x%"PRIX32" FunctionId=0x%"PRIX32"", - cbSize, InterfaceId, MessageId, FunctionId); - + cbSize, InterfaceId, MessageId, FunctionId); ZeroMemory(&ifman, sizeof(TSMF_IFMAN)); ifman.channel_callback = pChannelCallback; ifman.decoder_name = ((TSMF_PLUGIN*) callback->plugin)->decoder_name; @@ -179,12 +182,15 @@ static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, error = tsmf_ifman_rim_exchange_capability_request(&ifman); processed = TRUE; break; + case RIMCALL_RELEASE: case RIMCALL_QUERYINTERFACE: break; + default: break; } + break; case TSMF_INTERFACE_DEFAULT | STREAM_ID_PROXY: @@ -196,6 +202,7 @@ static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, error = ERROR_INVALID_DATA; goto out; } + CopyMemory(callback->presentation_id, Stream_Pointer(input), GUID_SIZE); Stream_Seek(input, GUID_SIZE); Stream_Read_UINT32(input, callback->stream_id); @@ -203,100 +210,125 @@ static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, ifman.output_pending = TRUE; processed = TRUE; break; + case EXCHANGE_CAPABILITIES_REQ: error = tsmf_ifman_exchange_capability_request(&ifman); processed = TRUE; break; + case CHECK_FORMAT_SUPPORT_REQ: error = tsmf_ifman_check_format_support_request(&ifman); processed = TRUE; break; + case ON_NEW_PRESENTATION: error = tsmf_ifman_on_new_presentation(&ifman); processed = TRUE; break; + case ADD_STREAM: error = tsmf_ifman_add_stream(&ifman, ((TSMF_PLUGIN*) callback->plugin)->rdpcontext); processed = TRUE; break; + case SET_TOPOLOGY_REQ: error = tsmf_ifman_set_topology_request(&ifman); processed = TRUE; break; + case REMOVE_STREAM: error = tsmf_ifman_remove_stream(&ifman); processed = TRUE; break; + case SET_SOURCE_VIDEO_RECT: error = tsmf_ifman_set_source_video_rect(&ifman); processed = TRUE; break; + case SHUTDOWN_PRESENTATION_REQ: error = tsmf_ifman_shutdown_presentation(&ifman); processed = TRUE; break; + case ON_STREAM_VOLUME: error = tsmf_ifman_on_stream_volume(&ifman); processed = TRUE; break; + case ON_CHANNEL_VOLUME: error = tsmf_ifman_on_channel_volume(&ifman); processed = TRUE; break; + case SET_VIDEO_WINDOW: error = tsmf_ifman_set_video_window(&ifman); processed = TRUE; break; + case UPDATE_GEOMETRY_INFO: error = tsmf_ifman_update_geometry_info(&ifman); processed = TRUE; break; + case SET_ALLOCATOR: error = tsmf_ifman_set_allocator(&ifman); processed = TRUE; break; + case NOTIFY_PREROLL: error = tsmf_ifman_notify_preroll(&ifman); processed = TRUE; break; + case ON_SAMPLE: error = tsmf_ifman_on_sample(&ifman); processed = TRUE; break; + case ON_FLUSH: error = tsmf_ifman_on_flush(&ifman); processed = TRUE; break; + case ON_END_OF_STREAM: error = tsmf_ifman_on_end_of_stream(&ifman); processed = TRUE; break; + case ON_PLAYBACK_STARTED: error = tsmf_ifman_on_playback_started(&ifman); processed = TRUE; break; + case ON_PLAYBACK_PAUSED: error = tsmf_ifman_on_playback_paused(&ifman); processed = TRUE; break; + case ON_PLAYBACK_RESTARTED: error = tsmf_ifman_on_playback_restarted(&ifman); processed = TRUE; break; + case ON_PLAYBACK_STOPPED: error = tsmf_ifman_on_playback_stopped(&ifman); processed = TRUE; break; + case ON_PLAYBACK_RATE_CHANGED: error = tsmf_ifman_on_playback_rate_changed(&ifman); processed = TRUE; break; + case RIMCALL_RELEASE: case RIMCALL_QUERYINTERFACE: break; + default: break; } + break; default: @@ -321,6 +353,7 @@ static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, processed = TRUE; ifman.output_pending = 1; break; + case RIMCALL_QUERYINTERFACE: /* [MS-RDPEXPS] 2.2.2.1.2 Query Interface Response (QI_RSP) This message is not supported in this channel. */ @@ -330,7 +363,9 @@ static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, if (!processed) { - WLog_ERR(TAG, "Unknown InterfaceId: 0x%08"PRIX32" MessageId: 0x%08"PRIX32" FunctionId: 0x%08"PRIX32"\n", InterfaceId, MessageId, FunctionId); + WLog_ERR(TAG, + "Unknown InterfaceId: 0x%08"PRIX32" MessageId: 0x%08"PRIX32" FunctionId: 0x%08"PRIX32"\n", + InterfaceId, MessageId, FunctionId); /* When a request is not implemented we return empty response indicating error */ } @@ -363,12 +398,11 @@ out: * * @return 0 on success, otherwise a Win32 error code */ -static UINT tsmf_on_close(IWTSVirtualChannelCallback *pChannelCallback) +static UINT tsmf_on_close(IWTSVirtualChannelCallback* pChannelCallback) { TSMF_STREAM* stream; TSMF_PRESENTATION* presentation; TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback; - DEBUG_TSMF(""); if (callback->stream_id) @@ -378,6 +412,7 @@ static UINT tsmf_on_close(IWTSVirtualChannelCallback *pChannelCallback) if (presentation) { stream = tsmf_stream_find_by_id(presentation, callback->stream_id); + if (stream) tsmf_stream_free(stream); } @@ -392,17 +427,15 @@ static UINT tsmf_on_close(IWTSVirtualChannelCallback *pChannelCallback) * * @return 0 on success, otherwise a Win32 error code */ -static UINT tsmf_on_new_channel_connection(IWTSListenerCallback *pListenerCallback, - IWTSVirtualChannel *pChannel, - BYTE *Data, - BOOL *pbAccept, - IWTSVirtualChannelCallback **ppCallback) +static UINT tsmf_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, + IWTSVirtualChannel* pChannel, + BYTE* Data, + BOOL* pbAccept, + IWTSVirtualChannelCallback** ppCallback) { TSMF_CHANNEL_CALLBACK* callback; TSMF_LISTENER_CALLBACK* listener_callback = (TSMF_LISTENER_CALLBACK*) pListenerCallback; - DEBUG_TSMF(""); - callback = (TSMF_CHANNEL_CALLBACK*) calloc(1, sizeof(TSMF_CHANNEL_CALLBACK)); if (!callback) @@ -414,9 +447,7 @@ static UINT tsmf_on_new_channel_connection(IWTSListenerCallback *pListenerCallba callback->plugin = listener_callback->plugin; callback->channel_mgr = listener_callback->channel_mgr; callback->channel = pChannel; - *ppCallback = (IWTSVirtualChannelCallback*) callback; - return CHANNEL_RC_OK; } @@ -429,9 +460,7 @@ static UINT tsmf_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManage { UINT status; TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*) pPlugin; - DEBUG_TSMF(""); - tsmf->listener_callback = (TSMF_LISTENER_CALLBACK*) calloc(1, sizeof(TSMF_LISTENER_CALLBACK)); if (!tsmf->listener_callback) @@ -440,12 +469,9 @@ static UINT tsmf_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManage tsmf->listener_callback->iface.OnNewChannelConnection = tsmf_on_new_channel_connection; tsmf->listener_callback->plugin = pPlugin; tsmf->listener_callback->channel_mgr = pChannelMgr; - status = pChannelMgr->CreateListener(pChannelMgr, "TSMF", 0, - (IWTSListenerCallback*) tsmf->listener_callback, &(tsmf->listener)); - + (IWTSListenerCallback*) tsmf->listener_callback, &(tsmf->listener)); tsmf->listener->pInterface = tsmf->iface.pInterface; - return status; } @@ -457,12 +483,9 @@ static UINT tsmf_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManage static UINT tsmf_plugin_terminated(IWTSPlugin* pPlugin) { TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*) pPlugin; - DEBUG_TSMF(""); - free(tsmf->listener_callback); free(tsmf); - return CHANNEL_RC_OK; } @@ -479,17 +502,16 @@ COMMAND_LINE_ARGUMENT_A tsmf_args[] = * * @return 0 on success, otherwise a Win32 error code */ -static UINT tsmf_process_addin_args(IWTSPlugin *pPlugin, ADDIN_ARGV *args) +static UINT tsmf_process_addin_args(IWTSPlugin* pPlugin, ADDIN_ARGV* args) { int status; DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*) pPlugin; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON; + status = CommandLineParseArgumentsA(args->argc, args->argv, + tsmf_args, flags, tsmf, NULL, NULL); - status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, - tsmf_args, flags, tsmf, NULL, NULL); if (status != 0) return ERROR_INVALID_DATA; @@ -499,22 +521,26 @@ static UINT tsmf_process_addin_args(IWTSPlugin *pPlugin, ADDIN_ARGV *args) { if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) continue; + CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "sys") { tsmf->audio_name = _strdup(arg->Value); + if (!tsmf->audio_name) return ERROR_OUTOFMEMORY; } CommandLineSwitchCase(arg, "dev") { tsmf->audio_device = _strdup(arg->Value); + if (!tsmf->audio_device) return ERROR_OUTOFMEMORY; } CommandLineSwitchCase(arg, "decoder") { tsmf->decoder_name = _strdup(arg->Value); + if (!tsmf->decoder_name) return ERROR_OUTOFMEMORY; } @@ -545,33 +571,32 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) TSMF_PLUGIN* tsmf; TsmfClientContext* context; UINT error = CHANNEL_RC_NO_MEMORY; - tsmf = (TSMF_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "tsmf"); if (!tsmf) { tsmf = (TSMF_PLUGIN*) calloc(1, sizeof(TSMF_PLUGIN)); + if (!tsmf) { WLog_ERR(TAG, "calloc failed!"); return CHANNEL_RC_NO_MEMORY; } - tsmf->iface.Initialize = tsmf_plugin_initialize; tsmf->iface.Connected = NULL; tsmf->iface.Disconnected = NULL; tsmf->iface.Terminated = tsmf_plugin_terminated; - tsmf->rdpcontext = ((freerdp*)((rdpSettings*) pEntryPoints->GetRdpSettings(pEntryPoints))->instance)->context; - + tsmf->rdpcontext = ((freerdp*)((rdpSettings*) pEntryPoints->GetRdpSettings( + pEntryPoints))->instance)->context; context = (TsmfClientContext*) calloc(1, sizeof(TsmfClientContext)); + if (!context) { WLog_ERR(TAG, "calloc failed!"); goto error_context; } - context->handle = (void*) tsmf; tsmf->iface.pInterface = (void*) context; @@ -590,7 +615,6 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) } return status; - error_init: free(context); error_context: diff --git a/channels/tsmf/client/tsmf_media.c b/channels/tsmf/client/tsmf_media.c index ada248c..05ca6c4 100644 --- a/channels/tsmf/client/tsmf_media.c +++ b/channels/tsmf/client/tsmf_media.c @@ -159,8 +159,8 @@ struct _TSMF_SAMPLE static wArrayList* presentation_list = NULL; static int TERMINATING = 0; -static void _tsmf_presentation_free(TSMF_PRESENTATION* presentation); -static void _tsmf_stream_free(TSMF_STREAM* stream); +static void _tsmf_presentation_free(void* obj); +static void _tsmf_stream_free(void* obj); static UINT64 get_current_time(void) { @@ -367,7 +367,7 @@ TSMF_PRESENTATION* tsmf_presentation_new(const BYTE* guid, goto error_stream_list; ArrayList_Object(presentation->stream_list)->fnObjectFree = - (OBJECT_FREE_FN) _tsmf_stream_free; + _tsmf_stream_free; if (ArrayList_Add(presentation_list, presentation) < 0) goto error_add; @@ -528,6 +528,7 @@ static BOOL tsmf_sample_playback_audio(TSMF_SAMPLE* sample) { ret = sample->stream->audio->Play(sample->stream->audio, sample->data, sample->decoded_size); + free(sample->data); sample->data = NULL; sample->decoded_size = 0; @@ -1193,14 +1194,19 @@ BOOL tsmf_stream_flush(TSMF_STREAM* stream) return TRUE; } -void _tsmf_presentation_free(TSMF_PRESENTATION* presentation) +void _tsmf_presentation_free(void* obj) { - tsmf_presentation_stop(presentation); - ArrayList_Clear(presentation->stream_list); - ArrayList_Free(presentation->stream_list); - free(presentation->rects); - ZeroMemory(presentation, sizeof(TSMF_PRESENTATION)); - free(presentation); + TSMF_PRESENTATION* presentation = (TSMF_PRESENTATION*)obj; + + if (presentation) + { + tsmf_presentation_stop(presentation); + ArrayList_Clear(presentation->stream_list); + ArrayList_Free(presentation->stream_list); + free(presentation->rects); + ZeroMemory(presentation, sizeof(TSMF_PRESENTATION)); + free(presentation); + } } void tsmf_presentation_free(TSMF_PRESENTATION* presentation) @@ -1414,8 +1420,10 @@ void tsmf_stream_end(TSMF_STREAM* stream, UINT32 message_id, stream->eos_channel_callback = pChannelCallback; } -void _tsmf_stream_free(TSMF_STREAM* stream) +void _tsmf_stream_free(void* obj) { + TSMF_STREAM* stream = (TSMF_STREAM*)obj; + if (!stream) return; @@ -1552,8 +1560,7 @@ BOOL tsmf_media_init(void) if (!presentation_list) return FALSE; - ArrayList_Object(presentation_list)->fnObjectFree = (OBJECT_FREE_FN) - _tsmf_presentation_free; + ArrayList_Object(presentation_list)->fnObjectFree = _tsmf_presentation_free; } return TRUE; diff --git a/channels/urbdrc/client/libusb/libusb_udevice.c b/channels/urbdrc/client/libusb/libusb_udevice.c index 94e1d04..6be973d 100644 --- a/channels/urbdrc/client/libusb/libusb_udevice.c +++ b/channels/urbdrc/client/libusb/libusb_udevice.c @@ -27,6 +27,7 @@ #endif #include +#include #include "libusb_udevice.h" @@ -532,7 +533,7 @@ static int udev_get_hub_handle(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_numb error = 0; WLog_DBG(TAG, " Port: %d", pdev->port_number); /* gen device path */ - sprintf(pdev->path, "ugen%"PRIu16".%"PRIu16"", bus_number, dev_number); + sprintf_s(pdev->path, ARRAYSIZE(pdev->path), "ugen%"PRIu16".%"PRIu16"", bus_number, dev_number); WLog_DBG(TAG, " DevPath: %s", pdev->path); break; } @@ -661,8 +662,7 @@ static int udev_get_hub_handle(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_numb } while (p1 != NULL); - memset(pdev->path, 0, 17); - strcpy(pdev->path, p2); + sprintf_s(pdev->path, ARRAYSIZE(pdev->path), "%s", p2); WLog_DBG(TAG, " DevPath: %s", pdev->path); /* query parent hub info */ dev = udev_device_get_parent(dev); @@ -1036,7 +1036,8 @@ static int libusb_udev_control_query_device_text(IUDEVICE* idev, UINT32 TextType case DeviceTextLocationInformation: bus_number = libusb_get_bus_number(pdev->libusb_dev); device_address = libusb_get_device_address(pdev->libusb_dev); - sprintf(deviceLocation, "Port_#%04"PRIu8".Hub_#%04"PRIu8"", device_address, bus_number); + sprintf_s(deviceLocation, ARRAYSIZE(deviceLocation), "Port_#%04"PRIu8".Hub_#%04"PRIu8"", + device_address, bus_number); for (i = 0; i < strlen(deviceLocation); i++) { diff --git a/channels/urbdrc/client/libusb/libusb_udevman.c b/channels/urbdrc/client/libusb/libusb_udevman.c index 2d15fed..b0d0fbc 100644 --- a/channels/urbdrc/client/libusb/libusb_udevman.c +++ b/channels/urbdrc/client/libusb/libusb_udevman.c @@ -484,7 +484,7 @@ static void urbdrc_udevman_register_devices(UDEVMAN* udevman, char* devices) dev_number = 0; idVendor = 0; idProduct = 0; - strcpy(hardware_id, token); + sprintf_s(hardware_id, ARRAYSIZE(hardware_id), "%s", token); token = strtok(NULL, "#"); if (udevman->flags & UDEVMAN_FLAG_ADD_BY_VID_PID) @@ -513,7 +513,7 @@ static void urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args) DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON; - status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, + status = CommandLineParseArgumentsA(args->argc, args->argv, urbdrc_udevman_args, flags, udevman, NULL, NULL); arg = urbdrc_udevman_args; diff --git a/channels/urbdrc/client/urbdrc_main.c b/channels/urbdrc/client/urbdrc_main.c index 04aee67..19b78b1 100644 --- a/channels/urbdrc/client/urbdrc_main.c +++ b/channels/urbdrc/client/urbdrc_main.c @@ -59,14 +59,14 @@ static int func_hardware_id_format(IUDEVICE* pdev, char(*HardwareIds)[DEVICE_HAR idProduct = (UINT16)pdev->query_device_descriptor(pdev, ID_PRODUCT); bcdDevice = (UINT16)pdev->query_device_descriptor(pdev, BCD_DEVICE); sprintf_s(str, sizeof(str), "USB\\VID_%04"PRIX16"&PID_%04"PRIX16"", idVendor, idProduct); - strcpy(HardwareIds[1], str); + strncpy(HardwareIds[1], str, DEVICE_HARDWARE_ID_SIZE); sprintf_s(str, sizeof(str), "%s&REV_%04"PRIX16"", HardwareIds[1], bcdDevice); - strcpy(HardwareIds[0], str); + strncpy(HardwareIds[0], str, DEVICE_HARDWARE_ID_SIZE); return 0; } static int func_compat_id_format(IUDEVICE* pdev, - char (*CompatibilityIds)[DEVICE_COMPATIBILITY_ID_SIZE]) + char(*CompatibilityIds)[DEVICE_COMPATIBILITY_ID_SIZE]) { char str[DEVICE_COMPATIBILITY_ID_SIZE]; UINT8 bDeviceClass, bDeviceSubClass, bDeviceProtocol; @@ -77,20 +77,20 @@ static int func_compat_id_format(IUDEVICE* pdev, if (!(pdev->isCompositeDevice(pdev))) { sprintf_s(str, sizeof(str), "USB\\Class_%02"PRIX8"", bDeviceClass); - strcpy(CompatibilityIds[2], str); + strncpy(CompatibilityIds[2], str, DEVICE_COMPATIBILITY_ID_SIZE); sprintf_s(str, sizeof(str), "%s&SubClass_%02"PRIX8"", CompatibilityIds[2], bDeviceSubClass); - strcpy(CompatibilityIds[1], str); + strncpy(CompatibilityIds[1], str, DEVICE_COMPATIBILITY_ID_SIZE); sprintf_s(str, sizeof(str), "%s&Prot_%02"PRIX8"", CompatibilityIds[1], bDeviceProtocol); - strcpy(CompatibilityIds[0], str); + strncpy(CompatibilityIds[0], str, DEVICE_COMPATIBILITY_ID_SIZE); } else { sprintf_s(str, sizeof(str), "USB\\DevClass_00"); - strcpy(CompatibilityIds[2], str); + strncpy(CompatibilityIds[2], str, DEVICE_COMPATIBILITY_ID_SIZE); sprintf_s(str, sizeof(str), "%s&SubClass_00", CompatibilityIds[2]); - strcpy(CompatibilityIds[1], str); + strncpy(CompatibilityIds[1], str, DEVICE_COMPATIBILITY_ID_SIZE); sprintf_s(str, sizeof(str), "%s&Prot_00", CompatibilityIds[1]); - strcpy(CompatibilityIds[0], str); + strncpy(CompatibilityIds[0], str, DEVICE_COMPATIBILITY_ID_SIZE); } return 0; @@ -1522,7 +1522,7 @@ static UINT urbdrc_process_addin_args(URBDRC_PLUGIN* urbdrc, ADDIN_ARGV* args) DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON; - status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, + status = CommandLineParseArgumentsA(args->argc, args->argv, urbdrc_args, flags, urbdrc, NULL, NULL); if (status < 0) diff --git a/channels/video/client/video_main.c b/channels/video/client/video_main.c index 20b4319..2258750 100755 --- a/channels/video/client/video_main.c +++ b/channels/video/client/video_main.c @@ -36,6 +36,7 @@ #include #include +#include #include #include #include diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 166847e..4c2e4df 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -89,7 +89,7 @@ if(${CMAKE_VERSION} VERSION_GREATER "2.8.10") export(PACKAGE freerdp-client) - set(FREERDP_CLIENT_CMAKE_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/FreeRDP-Client${FREERDP_VERSION_MAJOR}") + SetFreeRDPCMakeInstallDir(FREERDP_CLIENT_CMAKE_INSTALL_DIR "FreeRDP-Client${FREERDP_VERSION_MAJOR}") configure_package_config_file(FreeRDP-ClientConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FreeRDP-ClientConfig.cmake INSTALL_DESTINATION ${FREERDP_CLIENT_CMAKE_INSTALL_DIR} diff --git a/client/DirectFB/dfreerdp.c b/client/DirectFB/dfreerdp.c index 34bbf23..8e11b01 100644 --- a/client/DirectFB/dfreerdp.c +++ b/client/DirectFB/dfreerdp.c @@ -204,7 +204,6 @@ BOOL df_post_connect(freerdp* instance) instance->update->BeginPaint = df_begin_paint; instance->update->EndPaint = df_end_paint; df_keyboard_init(); - pointer_cache_register_callbacks(instance->update); df_register_graphics(instance->context->graphics); return TRUE; } diff --git a/client/Wayland/wlf_channels.c b/client/Wayland/wlf_channels.c index 38d66ef..c8a4c9d 100644 --- a/client/Wayland/wlf_channels.c +++ b/client/Wayland/wlf_channels.c @@ -39,9 +39,6 @@ static UINT wlf_encomsp_participant_created(EncomspClientContext* context, static void wlf_encomsp_init(wlfContext* wlf, EncomspClientContext* encomsp) { - if (!wlf) - return; - wlf->encomsp = encomsp; encomsp->custom = (void*) wlf; encomsp->ParticipantCreated = wlf_encomsp_participant_created; @@ -49,10 +46,14 @@ static void wlf_encomsp_init(wlfContext* wlf, EncomspClientContext* encomsp) static void wlf_encomsp_uninit(wlfContext* wlf, EncomspClientContext* encomsp) { - if (!wlf) - return; + if (encomsp) + { + encomsp->custom = NULL; + encomsp->ParticipantCreated = NULL; + } - wlf->encomsp = NULL; + if (wlf) + wlf->encomsp = NULL; } @@ -60,7 +61,9 @@ void wlf_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { wlfContext* wlf = (wlfContext*) context; - rdpSettings* settings = wlf->context.settings; + rdpSettings* settings; + + settings = wlf->context.settings; if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) { @@ -90,7 +93,9 @@ void wlf_OnChannelDisconnectedEventHandler(void* context, ChannelDisconnectedEventArgs* e) { wlfContext* wlf = (wlfContext*) context; - rdpSettings* settings = wlf->context.settings; + rdpSettings* settings; + + settings = wlf->context.settings; if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) { diff --git a/client/Wayland/wlf_input.c b/client/Wayland/wlf_input.c index 7b43c4c..2516cb4 100644 --- a/client/Wayland/wlf_input.c +++ b/client/Wayland/wlf_input.c @@ -25,22 +25,30 @@ #include "wlf_input.h" -BOOL wlf_handle_pointer_enter(freerdp *instance, UwacPointerEnterLeaveEvent *ev) { - rdpInput* input = instance->input; +BOOL wlf_handle_pointer_enter(freerdp* instance, UwacPointerEnterLeaveEvent* ev) +{ + if (!instance || !ev || !instance->input) + return FALSE; - return input->MouseEvent(input, PTR_FLAGS_MOVE, ev->x, ev->y); + return freerdp_input_send_mouse_event(instance->input, PTR_FLAGS_MOVE, ev->x, ev->y); } -BOOL wlf_handle_pointer_motion(freerdp *instance, UwacPointerMotionEvent *ev) { - rdpInput* input = instance->input; +BOOL wlf_handle_pointer_motion(freerdp* instance, UwacPointerMotionEvent* ev) +{ + if (!instance || !ev || !instance->input) + return FALSE; - return input->MouseEvent(input, PTR_FLAGS_MOVE, ev->x, ev->y); + return freerdp_input_send_mouse_event(instance->input, PTR_FLAGS_MOVE, ev->x, ev->y); } -BOOL wlf_handle_pointer_buttons(freerdp *instance, UwacPointerButtonEvent *ev) { +BOOL wlf_handle_pointer_buttons(freerdp* instance, UwacPointerButtonEvent* ev) +{ rdpInput* input; UINT16 flags; + if (!instance || !ev || !instance->input) + return FALSE; + input = instance->input; if (ev->state == WL_POINTER_BUTTON_STATE_PRESSED) @@ -53,45 +61,57 @@ BOOL wlf_handle_pointer_buttons(freerdp *instance, UwacPointerButtonEvent *ev) { case BTN_LEFT: flags |= PTR_FLAGS_BUTTON1; break; + case BTN_RIGHT: flags |= PTR_FLAGS_BUTTON2; break; + case BTN_MIDDLE: flags |= PTR_FLAGS_BUTTON3; break; + default: return TRUE; } - return input->MouseEvent(input, flags, ev->x, ev->y); + return freerdp_input_send_mouse_event(input, flags, ev->x, ev->y); } -BOOL wlf_handle_pointer_axis(freerdp *instance, UwacPointerAxisEvent *ev) { +BOOL wlf_handle_pointer_axis(freerdp* instance, UwacPointerAxisEvent* ev) +{ rdpInput* input; UINT16 flags; int direction; - input = instance->input; + if (!instance || !ev || !instance->input) + return FALSE; + input = instance->input; flags = PTR_FLAGS_WHEEL; if (ev->axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { direction = wl_fixed_to_int(ev->value); + if (direction < 0) flags |= 0x0078; else flags |= PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; } - return input->MouseEvent(input, flags, ev->x, ev->y); + return freerdp_input_send_mouse_event(input, flags, ev->x, ev->y); } -BOOL wlf_handle_key(freerdp *instance, UwacKeyEvent *ev) { - rdpInput* input = instance->input; +BOOL wlf_handle_key(freerdp* instance, UwacKeyEvent* ev) +{ + rdpInput* input; DWORD rdp_scancode; + if (!instance || !ev || !instance->input) + return FALSE; + + input = instance->input; rdp_scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(ev->raw_key + 8); if (rdp_scancode == RDP_SCANCODE_UNKNOWN) @@ -100,10 +120,14 @@ BOOL wlf_handle_key(freerdp *instance, UwacKeyEvent *ev) { return freerdp_input_send_keyboard_event_ex(input, ev->pressed, rdp_scancode); } -BOOL wlf_keyboard_enter(freerdp *instance, UwacKeyboardEnterLeaveEvent *ev) { - rdpInput* input = instance->input; +BOOL wlf_keyboard_enter(freerdp* instance, UwacKeyboardEnterLeaveEvent* ev) +{ + rdpInput* input; - return input->FocusInEvent(input, 0) && - input->MouseEvent(input, PTR_FLAGS_MOVE, 0, 0); + if (!instance || !ev || !instance->input) + return FALSE; + input = instance->input; + return freerdp_input_send_focus_in_event(input, 0) && + freerdp_input_send_mouse_event(input, PTR_FLAGS_MOVE, 0, 0); } diff --git a/client/Wayland/wlfreerdp.c b/client/Wayland/wlfreerdp.c index a68b7f7..eed827f 100644 --- a/client/Wayland/wlfreerdp.c +++ b/client/Wayland/wlfreerdp.c @@ -40,6 +40,9 @@ static BOOL wl_update_content(wlfContext* context_w) { + if (!context_w) + return FALSE; + if (!context_w->waitingFrameDone && context_w->haveDamage) { UwacWindowSubmitBuffer(context_w->window, true); @@ -53,7 +56,15 @@ static BOOL wl_update_content(wlfContext* context_w) static BOOL wl_begin_paint(rdpContext* context) { rdpGdi* gdi; + + if (!context || !context->gdi) + return FALSE; + gdi = context->gdi; + + if (!gdi->primary) + return FALSE; + gdi->primary->hdc->hwnd->invalid->null = TRUE; return TRUE; } @@ -66,7 +77,11 @@ static BOOL wl_end_paint(rdpContext* context) wlfContext* context_w; INT32 x, y; UINT32 w, h; - int i; + UINT32 i; + + if (!context || !context->gdi || !context->gdi->primary) + return FALSE; + gdi = context->gdi; if (gdi->primary->hdc->hwnd->invalid->null) @@ -117,7 +132,6 @@ static BOOL wl_pre_connect(freerdp* instance) settings->OsMajorType = OSMAJORTYPE_UNIX; settings->OsMinorType = OSMINORTYPE_NATIVE_WAYLAND; - settings->SoftwareGdi = TRUE; ZeroMemory(settings->OrderSupport, 32); settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE; settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE; @@ -132,9 +146,9 @@ static BOOL wl_pre_connect(freerdp* instance) settings->OrderSupport[NEG_LINETO_INDEX] = TRUE; settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE; settings->OrderSupport[NEG_MEMBLT_INDEX] = settings->BitmapCacheEnabled; - settings->OrderSupport[NEG_MEM3BLT_INDEX] = TRUE; + settings->OrderSupport[NEG_MEM3BLT_INDEX] = settings->BitmapCacheEnabled; settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = settings->BitmapCacheEnabled; - settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = FALSE; + settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = settings->BitmapCacheEnabled; settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE; settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = TRUE; settings->OrderSupport[NEG_FAST_INDEX_INDEX] = TRUE; @@ -177,6 +191,9 @@ static BOOL wl_post_connect(freerdp* instance) UwacWindow* window; wlfContext* context; + if (!instance || !instance->context) + return FALSE; + if (!gdi_init(instance, PIXEL_FORMAT_BGRA32)) return FALSE; @@ -245,7 +262,7 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display) context = (wlfContext*)instance->context; context->waitingFrameDone = FALSE; - if (context->haveDamage && !wl_end_paint(instance->context)) + if (context->haveDamage && !wl_update_content(context)) return FALSE; break; @@ -299,7 +316,7 @@ static int wlfreerdp_run(freerdp* instance) wlfContext* context; DWORD count; HANDLE handles[64]; - DWORD status; + DWORD status = WAIT_ABANDONED; if (!instance) return -1; @@ -315,20 +332,18 @@ static int wlfreerdp_run(freerdp* instance) return -1; } - handle_uwac_events(instance, context->display); - while (!freerdp_shall_disconnect(instance)) { handles[0] = context->displayHandle; - count = freerdp_get_event_handles(instance->context, &handles[1], 63); + count = freerdp_get_event_handles(instance->context, &handles[1], 63) + 1; - if (!count) + if (count <= 1) { printf("Failed to get FreeRDP file descriptor\n"); break; } - status = WaitForMultipleObjects(count + 1, handles, FALSE, INFINITE); + status = WaitForMultipleObjects(count, handles, FALSE, INFINITE); if (WAIT_FAILED == status) { @@ -342,7 +357,6 @@ static int wlfreerdp_run(freerdp* instance) break; } - //if (WaitForMultipleObjects(count, &handles[1], FALSE, INFINITE)) { if (freerdp_check_event_handles(instance->context) != TRUE) { if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_SUCCESS) @@ -350,15 +364,13 @@ static int wlfreerdp_run(freerdp* instance) break; } - - //} } freerdp_disconnect(instance); - return 0; + return status; } -static BOOL wlf_client_global_init() +static BOOL wlf_client_global_init(void) { setlocale(LC_ALL, ""); @@ -368,10 +380,24 @@ static BOOL wlf_client_global_init() return TRUE; } -static void wlf_client_global_uninit() +static void wlf_client_global_uninit(void) { } +static int wlf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type) +{ + wlfContext* wlf; + const char* str_data = freerdp_get_logon_error_info_data(data); + const char* str_type = freerdp_get_logon_error_info_type(type); + + if (!instance || !instance->context) + return -1; + + wlf = (wlfContext*) instance->context; + WLog_INFO(TAG, "Logon Error Info %s [%s]", str_data, str_type); + return 1; +} + static BOOL wlf_client_new(freerdp* instance, rdpContext* context) { UwacReturnCode status; @@ -387,7 +413,7 @@ static BOOL wlf_client_new(freerdp* instance, rdpContext* context) instance->GatewayAuthenticate = client_cli_gw_authenticate; instance->VerifyCertificate = client_cli_verify_certificate; instance->VerifyChangedCertificate = client_cli_verify_changed_certificate; - instance->LogonErrorInfo = NULL; + instance->LogonErrorInfo = wlf_logon_error_info; wfl->display = UwacOpenDisplay(NULL, &status); if (!wfl->display || (status != UWAC_SUCCESS)) @@ -448,8 +474,6 @@ int main(int argc, char* argv[]) DWORD status; RDP_CLIENT_ENTRY_POINTS clientEntryPoints; rdpContext* context; - //if (!handle_uwac_events(NULL, g_display)) - // exit(1); RdpClientEntry(&clientEntryPoints); context = freerdp_client_context_new(&clientEntryPoints); diff --git a/client/X11/CMakeLists.txt b/client/X11/CMakeLists.txt index e38e9b9..48e5af9 100644 --- a/client/X11/CMakeLists.txt +++ b/client/X11/CMakeLists.txt @@ -36,6 +36,8 @@ set(${MODULE_PREFIX}_SRCS xf_input.h xf_event.c xf_event.h + xf_floatbar.c + xf_floatbar.h xf_input.c xf_input.h xf_channels.c diff --git a/client/X11/generate_argument_docbook.c b/client/X11/generate_argument_docbook.c index 0dea546..b700539 100644 --- a/client/X11/generate_argument_docbook.c +++ b/client/X11/generate_argument_docbook.c @@ -11,65 +11,87 @@ LPSTR tr_esc_str(LPCSTR arg, bool format) LPSTR tmp = NULL; size_t cs = 0, x, ds, len; size_t s; - if(NULL == arg) + + if (NULL == arg) return NULL; + s = strlen(arg); + /* Find trailing whitespaces */ - while((s > 0) && isspace(arg[s-1])) + while ((s > 0) && isspace(arg[s - 1])) s--; + /* Prepare a initial buffer with the size of the result string. */ ds = s + 1; - if(s) + + if (s) tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); - if(NULL == tmp) + + if (NULL == tmp) { fprintf(stderr, "Could not allocate string buffer.\n"); exit(-2); } + /* Copy character for character and check, if it is necessary to escape. */ memset(tmp, 0, ds * sizeof(CHAR)); - for(x=0; x", len); - else - strncpy (&tmp[cs], "<", len); + /* coverity[buffer_size] */ + strncpy(&tmp[cs], "", len); + else + /* coverity[buffer_size] */ + strncpy(&tmp[cs], "<", len); + cs += len; break; + case '>': len = format ? 14 : 4; ds += len - 1; tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); - if(NULL == tmp) + + if (NULL == tmp) { fprintf(stderr, "Could not reallocate string buffer.\n"); exit(-4); } + if (format) - strncpy (&tmp[cs], "", len); - else - strncpy (&tmp[cs], "<", len); + /* coverity[buffer_size] */ + strncpy(&tmp[cs], "", len); + else + /* coverity[buffer_size] */ + strncpy(&tmp[cs], "<", len); + cs += len; break; + case '\'': ds += 5; tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); - if(NULL == tmp) + + if (NULL == tmp) { fprintf(stderr, "Could not reallocate string buffer.\n"); exit(-5); } + tmp[cs++] = '&'; tmp[cs++] = 'a'; tmp[cs++] = 'p'; @@ -77,14 +99,17 @@ LPSTR tr_esc_str(LPCSTR arg, bool format) tmp[cs++] = 's'; tmp[cs++] = ';'; break; + case '"': ds += 5; tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); - if(NULL == tmp) + + if (NULL == tmp) { fprintf(stderr, "Could not reallocate string buffer.\n"); exit(-6); } + tmp[cs++] = '&'; tmp[cs++] = 'q'; tmp[cs++] = 'u'; @@ -92,88 +117,101 @@ LPSTR tr_esc_str(LPCSTR arg, bool format) tmp[cs++] = 't'; tmp[cs++] = ';'; break; + case '&': ds += 4; tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); - if(NULL == tmp) + + if (NULL == tmp) { fprintf(stderr, "Could not reallocate string buffer.\n"); exit(-7); } + tmp[cs++] = '&'; tmp[cs++] = 'a'; tmp[cs++] = 'm'; tmp[cs++] = 'p'; tmp[cs++] = ';'; break; + default: tmp[cs++] = arg[x]; break; } + /* Assure, the string is '\0' terminated. */ - tmp[ds-1] = '\0'; + tmp[ds - 1] = '\0'; } + return tmp; } -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) { - size_t elements = sizeof(args)/sizeof(args[0]); + size_t elements = sizeof(args) / sizeof(args[0]); size_t x; - const char *fname = "xfreerdp-argument.1.xml"; - FILE *fp = NULL; + const char* fname = "xfreerdp-argument.1.xml"; + FILE* fp = NULL; /* Open output file for writing, truncate if existing. */ fp = fopen(fname, "w"); - if(NULL == fp) + + if (NULL == fp) { fprintf(stderr, "Could not open '%s' for writing.\n", fname); return -1; } + /* The tag used as header in the manpage */ fprintf(fp, "\n"); fprintf(fp, "\tOptions\n"); fprintf(fp, "\t\t\n"); + /* Iterate over argument struct and write data to docbook 4.5 * compatible XML */ - if(elements < 2) + if (elements < 2) { fprintf(stderr, "The argument array 'args' is empty, writing an empty file.\n"); elements = 1; } - for(x=0; xName, FALSE); - char *alias = tr_esc_str((LPSTR) arg->Alias, FALSE); - char *format = tr_esc_str(arg->Format, TRUE); - char *text = tr_esc_str((LPSTR) arg->Text, FALSE); + for (x = 0; x < elements - 1; x++) + { + const COMMAND_LINE_ARGUMENT_A* arg = &args[x]; + char* name = tr_esc_str((LPSTR) arg->Name, FALSE); + char* alias = tr_esc_str((LPSTR) arg->Alias, FALSE); + char* format = tr_esc_str(arg->Format, TRUE); + char* text = tr_esc_str((LPSTR) arg->Text, FALSE); fprintf(fp, "\t\t\t\n"); do { fprintf(fp, "\t\t\t\t", name); if (format) { if (arg->Flags == COMMAND_LINE_VALUE_OPTIONAL) fprintf(fp, "["); + fprintf(fp, ":%s", format); + if (arg->Flags == COMMAND_LINE_VALUE_OPTIONAL) fprintf(fp, "]"); } fprintf(fp, "\n"); - + if (alias == name) break; - free (name); + free(name); name = alias; } while (alias); @@ -190,19 +228,21 @@ int main(int argc, char *argv[]) fprintf(fp, " (default:%s)", arg->Default ? "on" : "off"); else if (arg->Default) { - char *value = tr_esc_str((LPSTR) arg->Default, FALSE); + char* value = tr_esc_str((LPSTR) arg->Default, FALSE); fprintf(fp, " (default:%s)", value); - free (value); + free(value); } fprintf(fp, "\n"); fprintf(fp, "\t\t\t\t\n"); } + fprintf(fp, "\t\t\t\n"); free(name); free(format); free(text); } + fprintf(fp, "\t\t\n"); fprintf(fp, "\t\n"); fclose(fp); diff --git a/client/X11/resource/close.xbm b/client/X11/resource/close.xbm new file mode 100644 index 0000000..45c60e3 --- /dev/null +++ b/client/X11/resource/close.xbm @@ -0,0 +1,11 @@ +#define close_width 24 +#define close_height 24 +static unsigned char close_bits[] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x7c, 0xfe, 0xff, 0x38, 0xfe, 0xff, 0x11, 0xff, 0xff, 0x83, 0xff, + 0xff, 0xc7, 0xff, 0xff, 0x83, 0xff, 0xff, 0x11, 0xff, 0xff, 0x38, 0xfe, + 0xff, 0x7c, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; diff --git a/client/X11/resource/lock.xbm b/client/X11/resource/lock.xbm new file mode 100644 index 0000000..12340f5 --- /dev/null +++ b/client/X11/resource/lock.xbm @@ -0,0 +1,11 @@ +#define lock_width 24 +#define lock_height 24 +static unsigned char lock_bits[] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, + 0xff, 0x83, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xc7, 0xff, + 0xff, 0x00, 0xfe, 0xff, 0x00, 0xfe, 0xff, 0xef, 0xff, 0xff, 0xef, 0xff, + 0xff, 0xef, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; diff --git a/client/X11/resource/minimize.xbm b/client/X11/resource/minimize.xbm new file mode 100644 index 0000000..c69d861 --- /dev/null +++ b/client/X11/resource/minimize.xbm @@ -0,0 +1,11 @@ +#define minimize_width 24 +#define minimize_height 24 +static unsigned char minimize_bits[] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xfc, + 0x3f, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; diff --git a/client/X11/resource/restore.xbm b/client/X11/resource/restore.xbm new file mode 100644 index 0000000..e9909f5 --- /dev/null +++ b/client/X11/resource/restore.xbm @@ -0,0 +1,11 @@ +#define restore_width 24 +#define restore_height 24 +static unsigned char restore_bits[] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x03, 0xff, 0xff, 0x03, 0xff, 0xff, 0x3b, 0xff, 0x7f, 0x20, 0xff, + 0x7f, 0x20, 0xff, 0x7f, 0x07, 0xff, 0x7f, 0xe7, 0xff, 0x7f, 0xe7, 0xff, + 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; diff --git a/client/X11/resource/unlock.xbm b/client/X11/resource/unlock.xbm new file mode 100644 index 0000000..a809126 --- /dev/null +++ b/client/X11/resource/unlock.xbm @@ -0,0 +1,11 @@ +#define unlock_width 24 +#define unlock_height 24 +static unsigned char unlock_bits[] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf3, 0xff, 0xff, 0xf3, 0xff, 0xff, 0x73, 0xfe, 0xff, 0x03, 0xfe, + 0x3f, 0x00, 0xfe, 0xff, 0x03, 0xfe, 0xff, 0x73, 0xfe, 0xff, 0xf3, 0xff, + 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; diff --git a/client/X11/xf_channels.c b/client/X11/xf_channels.c index 17029a5..ef91504 100644 --- a/client/X11/xf_channels.c +++ b/client/X11/xf_channels.c @@ -68,7 +68,7 @@ void xf_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* } else if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0) { - xf_disp_init(xfc, (DispClientContext*)e->pInterface); + xf_disp_init(xfc->xfDisp, (DispClientContext*)e->pInterface); } else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0) { @@ -96,6 +96,10 @@ void xf_OnChannelDisconnectedEventHandler(void* context, ChannelDisconnectedEven { xfc->rdpei = NULL; } + else if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0) + { + xf_disp_uninit(xfc->xfDisp, (DispClientContext*)e->pInterface); + } else if (strcmp(e->name, TSMF_DVC_CHANNEL_NAME) == 0) { xf_tsmf_uninit(xfc, (TsmfClientContext*) e->pInterface); diff --git a/client/X11/xf_channels.h b/client/X11/xf_channels.h index ac91f84..8a8c3b1 100644 --- a/client/X11/xf_channels.h +++ b/client/X11/xf_channels.h @@ -32,9 +32,6 @@ #include #include -int xf_on_channel_connected(freerdp* instance, const char* name, void* pInterface); -int xf_on_channel_disconnected(freerdp* instance, const char* name, void* pInterface); - void xf_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e); void xf_OnChannelDisconnectedEventHandler(void* context, ChannelDisconnectedEventArgs* e); diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index fba5b4a..4a3e0d2 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -50,10 +50,6 @@ #include #endif -#ifdef WITH_XI -#include -#endif - #include #include @@ -105,6 +101,7 @@ #include "xf_channels.h" #include "xfreerdp.h" + #include #define TAG CLIENT_TAG("x11") @@ -287,11 +284,6 @@ static BOOL xf_desktop_resize(rdpContext* context) return TRUE; } -static BOOL xf_sw_begin_paint(rdpContext* context) -{ - return TRUE; -} - static BOOL xf_sw_end_paint(rdpContext* context) { int i; @@ -394,11 +386,6 @@ out: return ret; } -static BOOL xf_hw_begin_paint(rdpContext* context) -{ - return TRUE; -} - static BOOL xf_hw_end_paint(rdpContext* context) { INT32 x, y; @@ -555,16 +542,26 @@ BOOL xf_create_window(xfContext* xfc) } else if (settings->ServerPort == 3389) { - windowTitle = malloc(1 + sizeof("FreeRDP: ") + strlen( - settings->ServerHostname)); - sprintf(windowTitle, "FreeRDP: %s", settings->ServerHostname); + size_t size = 1 + sizeof("FreeRDP: ") + strlen( + settings->ServerHostname); + windowTitle = malloc(size); + + if (!windowTitle) + return FALSE; + + sprintf_s(windowTitle, size, "FreeRDP: %s", settings->ServerHostname); } else { - windowTitle = malloc(1 + sizeof("FreeRDP: ") + strlen(settings->ServerHostname) - + sizeof(":00000")); - sprintf(windowTitle, "FreeRDP: %s:%i", settings->ServerHostname, - settings->ServerPort); + size_t size = 1 + sizeof("FreeRDP: ") + strlen(settings->ServerHostname) + + sizeof(":00000"); + windowTitle = malloc(size); + + if (!windowTitle) + return FALSE; + + sprintf_s(windowTitle, size, "FreeRDP: %s:%i", settings->ServerHostname, + settings->ServerPort); } #ifdef WITH_XRENDER @@ -707,6 +704,16 @@ void xf_toggle_fullscreen(xfContext* xfc) WindowStateChangeEventArgs e; rdpContext* context = (rdpContext*) xfc; rdpSettings* settings = context->settings; + + /* + when debugging, ungrab keyboard when toggling fullscreen + to allow keyboard usage on the debugger + */ + if (xfc->debug) + { + XUngrabKeyboard(xfc->display, CurrentTime); + } + xfc->fullscreen = (xfc->fullscreen) ? FALSE : TRUE; xfc->decorations = (xfc->fullscreen) ? FALSE : settings->Decorations; xf_SetWindowFullscreen(xfc, xfc->window, xfc->fullscreen); @@ -1111,9 +1118,9 @@ static BOOL xf_pre_connect(freerdp* instance) settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = settings->BitmapCacheEnabled; settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = settings->BitmapCacheEnabled; settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE; - settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = TRUE; - settings->OrderSupport[NEG_FAST_INDEX_INDEX] = TRUE; - settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = TRUE; + settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = settings->GlyphSupportLevel != GLYPH_SUPPORT_NONE; + settings->OrderSupport[NEG_FAST_INDEX_INDEX] = settings->GlyphSupportLevel != GLYPH_SUPPORT_NONE; + settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = settings->GlyphSupportLevel != GLYPH_SUPPORT_NONE; settings->OrderSupport[NEG_POLYGON_SC_INDEX] = FALSE; settings->OrderSupport[NEG_POLYGON_CB_INDEX] = FALSE; settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE; @@ -1126,7 +1133,7 @@ static BOOL xf_pre_connect(freerdp* instance) if (!freerdp_client_load_addins(channels, instance->settings)) return FALSE; - if (!settings->Username && !settings->CredentialsFromStdin) + if (!settings->Username && !settings->CredentialsFromStdin && !settings->SmartcardLogon) { char* login_name = getlogin(); @@ -1182,6 +1189,7 @@ static BOOL xf_pre_connect(freerdp* instance) xfc->decorations = settings->Decorations; xfc->grab_keyboard = settings->GrabKeyboard; xfc->fullscreen_toggle = settings->ToggleFullscreen; + xfc->floatbar = settings->Floatbar; xf_button_map_init(xfc); return TRUE; } @@ -1257,18 +1265,15 @@ static BOOL xf_post_connect(freerdp* instance) if (settings->SoftwareGdi) { - update->BeginPaint = xf_sw_begin_paint; update->EndPaint = xf_sw_end_paint; update->DesktopResize = xf_sw_desktop_resize; } else { - update->BeginPaint = xf_hw_begin_paint; update->EndPaint = xf_hw_end_paint; update->DesktopResize = xf_hw_desktop_resize; } - pointer_cache_register_callbacks(update); update->PlaySound = xf_play_sound; update->SetKeyboardIndicators = xf_keyboard_set_indicators; update->SetKeyboardImeStatus = xf_keyboard_set_ime_status; @@ -1299,6 +1304,10 @@ static void xf_post_disconnect(freerdp* instance) context = instance->context; xfc = (xfContext*) context; + PubSub_UnsubscribeChannelConnected(instance->context->pubSub, + xf_OnChannelConnectedEventHandler); + PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub, + xf_OnChannelDisconnectedEventHandler); gdi_free(instance); if (xfc->clipboard) @@ -1414,46 +1423,25 @@ static DWORD WINAPI xf_input_thread(LPVOID arg) return 0; } -static BOOL xf_auto_reconnect(freerdp* instance) +static BOOL handle_window_events(freerdp* instance) { - UINT32 maxRetries; - UINT32 numRetries = 0; - rdpSettings* settings = instance->settings; - maxRetries = settings->AutoReconnectMaxRetries; + rdpSettings* settings; - /* Only auto reconnect on network disconnects. */ - if (freerdp_error_info(instance) != 0) + if (!instance || !instance->settings) return FALSE; - /* A network disconnect was detected */ - WLog_INFO(TAG, "Network disconnect!"); + settings = instance->settings; - if (!settings->AutoReconnectionEnabled) + if (!settings->AsyncInput) { - /* No auto-reconnect - just quit */ - return FALSE; - } - - /* Perform an auto-reconnect. */ - while (TRUE) - { - /* Quit retrying if max retries has been exceeded */ - if ((maxRetries > 0) && (numRetries++ >= maxRetries)) + if (!xf_process_x_events(instance)) { + WLog_INFO(TAG, "Closed from X11"); return FALSE; } - - /* Attempt the next reconnect */ - WLog_INFO(TAG, "Attempting reconnect (%"PRIu32" of %"PRIu32")", numRetries, maxRetries); - - if (freerdp_reconnect(instance)) - return TRUE; - - sleep(5); } - WLog_ERR(TAG, "Maximum reconnect retries exceeded"); - return FALSE; + return TRUE; } /** Main loop for the rdp connection. @@ -1490,6 +1478,8 @@ static DWORD WINAPI xf_client_thread(LPVOID param) if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_AUTHENTICATION_FAILED) exit_code = XF_EXIT_AUTH_FAILURE; + else if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED) + exit_code = XF_EXIT_NEGO_FAILURE; else exit_code = XF_EXIT_CONN_FAILED; } @@ -1536,12 +1526,9 @@ static DWORD WINAPI xf_client_thread(LPVOID param) goto disconnect; } - handles[0] = timer; - if (!settings->AsyncInput) { inputEvent = xfc->x11event; - handles[1] = inputEvent; } else { @@ -1555,6 +1542,12 @@ static DWORD WINAPI xf_client_thread(LPVOID param) while (!freerdp_shall_disconnect(instance)) { + nCount = 0; + handles[nCount++] = timer; + + if (!settings->AsyncInput) + handles[nCount++] = inputEvent; + /* * win8 and server 2k12 seem to have some timing issue/race condition * when a initial sync request is send to sync the keyboard indicators @@ -1566,11 +1559,8 @@ static DWORD WINAPI xf_client_thread(LPVOID param) xf_keyboard_focus_in(xfc); } - nCount = (settings->AsyncInput) ? 1 : 2; - - if (!settings->AsyncTransport) { - DWORD tmp = freerdp_get_event_handles(context, &handles[nCount], 64 - nCount); + DWORD tmp = freerdp_get_event_handles(context, &handles[nCount], ARRAYSIZE(handles) - nCount); if (tmp == 0) { @@ -1581,17 +1571,28 @@ static DWORD WINAPI xf_client_thread(LPVOID param) nCount += tmp; } + if (xfc->floatbar && xfc->fullscreen && !xfc->remote_app) + xf_floatbar_hide_and_show(xfc); + waitStatus = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE); if (waitStatus == WAIT_FAILED) break; - if (!settings->AsyncTransport) { if (!freerdp_check_event_handles(context)) { - if (xf_auto_reconnect(instance)) + if (client_auto_reconnect_ex(instance, handle_window_events)) continue; + else + { + /* + * Indicate an unsuccessful connection attempt if reconnect + * did not succeed and no other error was specified. + */ + if (freerdp_error_info(instance) == 0) + exit_code = XF_EXIT_CONN_FAILED; + } if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS) WLog_ERR(TAG, "Failed to check FreeRDP file descriptor"); @@ -1600,14 +1601,8 @@ static DWORD WINAPI xf_client_thread(LPVOID param) } } - if (!settings->AsyncInput) - { - if (!xf_process_x_events(instance)) - { - WLog_INFO(TAG, "Closed from X11"); - break; - } - } + if (!handle_window_events(instance)) + break; if ((status != WAIT_TIMEOUT) && (waitStatus == WAIT_OBJECT_0)) { @@ -1623,8 +1618,19 @@ static DWORD WINAPI xf_client_thread(LPVOID param) } if (!exit_code) + { exit_code = freerdp_error_info(instance); + if (exit_code == XF_EXIT_DISCONNECT && + freerdp_get_disconnect_ultimatum(context) == Disconnect_Ultimatum_user_requested) + { + /* This situation might be limited to Windows XP. */ + WLog_INFO(TAG, + "Error info says user did not initiate but disconnect ultimatum says they did; treat this as a user logoff"); + exit_code = XF_EXIT_LOGOFF; + } + } + disconnect: if (timer) @@ -1639,7 +1645,7 @@ end: DWORD xf_exit_code_from_disconnect_reason(DWORD reason) { if (reason == 0 || (reason >= XF_EXIT_PARSE_ARGUMENTS - && reason <= XF_EXIT_AUTH_FAILURE)) + && reason <= XF_EXIT_NEGO_FAILURE)) return reason; /* License error set */ else if (reason >= 0x100 && reason <= 0x10A) @@ -1794,7 +1800,8 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context) xf_PanningChangeEventHandler); #endif xfc->UseXThreads = TRUE; - //xfc->debug = TRUE; + /* uncomment below if debugging to prevent keyboard grap */ + /* xfc->debug = TRUE; */ if (xfc->UseXThreads) { @@ -1876,6 +1883,8 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context) "_NET_WM_WINDOW_TYPE_DIALOG", False); xfc->_NET_WM_WINDOW_TYPE_POPUP = XInternAtom(xfc->display, "_NET_WM_WINDOW_TYPE_POPUP", False); + xfc->_NET_WM_WINDOW_TYPE_POPUP_MENU = XInternAtom(xfc->display, + "_NET_WM_WINDOW_TYPE_POPUP_MENU", False); xfc->_NET_WM_WINDOW_TYPE_UTILITY = XInternAtom(xfc->display, "_NET_WM_WINDOW_TYPE_UTILITY", False); xfc->_NET_WM_WINDOW_TYPE_DROPDOWN_MENU = XInternAtom(xfc->display, @@ -1945,6 +1954,15 @@ static void xfreerdp_client_free(freerdp* instance, rdpContext* context) if (!context) return; + PubSub_UnsubscribeTerminate(context->pubSub, + xf_TerminateEventHandler); +#ifdef WITH_XRENDER + PubSub_UnsubscribeZoomingChange(context->pubSub, + xf_ZoomingChangeEventHandler); + PubSub_UnsubscribePanningChange(context->pubSub, + xf_PanningChangeEventHandler); +#endif + if (xfc->display) { XCloseDisplay(xfc->display); diff --git a/client/X11/xf_cliprdr.c b/client/X11/xf_cliprdr.c index e141e19..1c86031 100644 --- a/client/X11/xf_cliprdr.c +++ b/client/X11/xf_cliprdr.c @@ -1358,7 +1358,7 @@ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext* UINT32 dstFormatId; BOOL nullTerminated = FALSE; UINT32 size = formatDataResponse->dataLen; - BYTE* data = formatDataResponse->requestedFormatData; + const BYTE* data = formatDataResponse->requestedFormatData; xfClipboard* clipboard = (xfClipboard*) context->custom; xfContext* xfc = clipboard->xfc; @@ -1411,6 +1411,9 @@ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext* srcFormatId = CF_DIB; dstFormatId = ClipboardGetFormatId(clipboard->system, "image/bmp"); break; + + default: + break; } } @@ -1419,9 +1422,23 @@ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext* if (bSuccess) { + if (SrcSize == 0) + { + WLog_INFO(TAG, "skipping, empty data detected!!!"); + return CHANNEL_RC_OK; + } + DstSize = 0; pDstData = (BYTE*) ClipboardGetData(clipboard->system, dstFormatId, &DstSize); + if (!pDstData) + { + WLog_ERR(TAG, "failed to get clipboard data in format %s [source format %s]", + ClipboardGetFormatName(clipboard->system, dstFormatId), + ClipboardGetFormatName(clipboard->system, srcFormatId)); + return ERROR_INTERNAL_ERROR; + } + if (nullTerminated) { while (DstSize > 0 && pDstData[DstSize - 1] == '\0') diff --git a/client/X11/xf_disp.c b/client/X11/xf_disp.c index 49d9601..1b30976 100644 --- a/client/X11/xf_disp.c +++ b/client/X11/xf_disp.c @@ -39,7 +39,8 @@ struct _xfDispContext { - xfContext *xfc; + xfContext* xfc; + DispClientContext* disp; BOOL haveXRandr; int eventBase, errorBase; int lastSentWidth, lastSentHeight; @@ -47,37 +48,107 @@ struct _xfDispContext int targetWidth, targetHeight; BOOL activated; BOOL waitingResize; + BOOL fullscreen; + UINT16 lastSentDesktopOrientation; + UINT32 lastSentDesktopScaleFactor; + UINT32 lastSentDeviceScaleFactor; }; +static UINT xf_disp_sendLayout(DispClientContext* disp, rdpMonitor* monitors, int nmonitors); -static BOOL xf_disp_sendResize(xfDispContext *xfDisp, int width, int height) +static BOOL xf_disp_settings_changed(xfDispContext* xfDisp) { - DISPLAY_CONTROL_MONITOR_LAYOUT layout; - xfContext *xfc = xfDisp->xfc; - rdpSettings *settings = xfc->context.settings; + rdpSettings* settings = xfDisp->xfc->context.settings; - xfDisp->lastSentDate = GetTickCount64(); - xfDisp->lastSentWidth = width; - xfDisp->lastSentHeight = height; - xfDisp->waitingResize = TRUE; + if (xfDisp->lastSentWidth != xfDisp->targetWidth) + return TRUE; - layout.Flags = DISPLAY_CONTROL_MONITOR_PRIMARY; - layout.Top = layout.Left = 0; - layout.Width = width; - layout.Height = height; - layout.Orientation = ORIENTATION_LANDSCAPE; - layout.DesktopScaleFactor = settings->DesktopScaleFactor; - layout.DeviceScaleFactor = settings->DeviceScaleFactor; - layout.PhysicalWidth = width; - layout.PhysicalHeight = height; + if (xfDisp->lastSentHeight != xfDisp->targetHeight) + return TRUE; - return xfc->disp->SendMonitorLayout(xfc->disp, 1, &layout) == CHANNEL_RC_OK; + if (xfDisp->lastSentDesktopOrientation != settings->DesktopOrientation) + return TRUE; + + if (xfDisp->lastSentDesktopScaleFactor != settings->DesktopScaleFactor) + return TRUE; + + if (xfDisp->lastSentDeviceScaleFactor != settings->DeviceScaleFactor) + return TRUE; + + if (xfDisp->fullscreen != xfDisp->xfc->fullscreen) + return TRUE; + + return FALSE; } - -static BOOL xf_disp_set_window_resizable(xfDispContext *xfDisp) +static BOOL xf_update_last_sent(xfDispContext* xfDisp) { - XSizeHints *size_hints; + rdpSettings* settings = xfDisp->xfc->context.settings; + xfDisp->lastSentWidth = xfDisp->targetWidth; + xfDisp->lastSentHeight = xfDisp->targetHeight; + xfDisp->lastSentDesktopOrientation = settings->DesktopOrientation; + xfDisp->lastSentDesktopScaleFactor = settings->DesktopScaleFactor; + xfDisp->lastSentDeviceScaleFactor = settings->DeviceScaleFactor; + xfDisp->fullscreen = xfDisp->xfc->fullscreen; + return TRUE; +} + +static BOOL xf_disp_sendResize(xfDispContext* xfDisp) +{ + DISPLAY_CONTROL_MONITOR_LAYOUT layout; + xfContext* xfc; + rdpSettings* settings; + + if (!xfDisp || !xfDisp->xfc) + return FALSE; + + xfc = xfDisp->xfc; + settings = xfc->context.settings; + + if (!settings) + return FALSE; + + if (!xfDisp->activated || !xfDisp->disp) + return TRUE; + + if (GetTickCount64() - xfDisp->lastSentDate < RESIZE_MIN_DELAY) + return TRUE; + + xfDisp->lastSentDate = GetTickCount64(); + + if (!xf_disp_settings_changed(xfDisp)) + return TRUE; + + if (xfc->fullscreen && (settings->MonitorCount > 0)) + { + if (xf_disp_sendLayout(xfDisp->disp, settings->MonitorDefArray, + settings->MonitorCount) != CHANNEL_RC_OK) + return FALSE; + } + else + { + xfDisp->waitingResize = TRUE; + layout.Flags = DISPLAY_CONTROL_MONITOR_PRIMARY; + layout.Top = layout.Left = 0; + layout.Width = xfDisp->targetWidth; + layout.Height = xfDisp->targetHeight; + layout.Orientation = settings->DesktopOrientation; + layout.DesktopScaleFactor = settings->DesktopScaleFactor; + layout.DeviceScaleFactor = settings->DeviceScaleFactor; + layout.PhysicalWidth = xfDisp->targetWidth; + layout.PhysicalHeight = xfDisp->targetHeight; + + if (IFCALLRESULT(CHANNEL_RC_OK, xfDisp->disp->SendMonitorLayout, xfDisp->disp, 1, + &layout) != CHANNEL_RC_OK) + return FALSE; + } + + return xf_update_last_sent(xfDisp); +} + +static BOOL xf_disp_set_window_resizable(xfDispContext* xfDisp) +{ + XSizeHints* size_hints; if (!(size_hints = XAllocSizeHints())) return FALSE; @@ -86,18 +157,44 @@ static BOOL xf_disp_set_window_resizable(xfDispContext *xfDisp) size_hints->win_gravity = NorthWestGravity; size_hints->min_width = size_hints->min_height = 320; size_hints->max_width = size_hints->max_height = 8192; + if (xfDisp->xfc->window) XSetWMNormalHints(xfDisp->xfc->display, xfDisp->xfc->window->handle, size_hints); + XFree(size_hints); return TRUE; } +static BOOL xf_disp_check_context(void* context, xfContext** ppXfc, xfDispContext** ppXfDisp, + rdpSettings** ppSettings) +{ + xfContext* xfc; + + if (!context) + return FALSE; + + xfc = (xfContext*)context; + + if (!(xfc->xfDisp)) + return FALSE; + + if (!xfc->context.settings) + return FALSE; + + *ppXfc = xfc; + *ppXfDisp = xfc->xfDisp; + *ppSettings = xfc->context.settings; + return TRUE; +} static void xf_disp_OnActivated(void* context, ActivatedEventArgs* e) { - xfContext *xfc = (xfContext *)context; - xfDispContext *xfDisp = xfc->xfDisp; - rdpSettings *settings = xfc->context.settings; + xfContext* xfc; + xfDispContext* xfDisp; + rdpSettings* settings; + + if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings)) + return; xfDisp->waitingResize = FALSE; @@ -108,102 +205,96 @@ static void xf_disp_OnActivated(void* context, ActivatedEventArgs* e) if (e->firstActivation) return; - /* if a resize has been done recently don't do anything and let the timer - * perform the resize */ - if (GetTickCount64() - xfDisp->lastSentDate < RESIZE_MIN_DELAY) - return; - - if ((xfDisp->lastSentWidth != xfDisp->targetWidth) || (xfDisp->lastSentHeight != xfDisp->targetHeight)) - { - WLog_DBG(TAG, "performing delayed resize to %dx%d", xfDisp->targetWidth, xfDisp->targetHeight); - xf_disp_sendResize(xfDisp, xfDisp->targetWidth, xfDisp->targetHeight); - } + xf_disp_sendResize(xfDisp); } } - static void xf_disp_OnGraphicsReset(void* context, GraphicsResetEventArgs* e) { - xfContext *xfc = (xfContext *)context; - xfDispContext *xfDisp = xfc->xfDisp; - rdpSettings *settings = xfc->context.settings; + xfContext* xfc; + xfDispContext* xfDisp; + rdpSettings* settings; + + if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings)) + return; xfDisp->waitingResize = FALSE; if (xfDisp->activated && !settings->Fullscreen) { xf_disp_set_window_resizable(xfDisp); - - /* if a resize has been done recently don't do anything and let the timer - * perform the resize */ - if (GetTickCount64() - xfDisp->lastSentDate < RESIZE_MIN_DELAY) - return; - - if ((xfDisp->lastSentWidth != xfDisp->targetWidth) || (xfDisp->lastSentHeight != xfDisp->targetHeight)) - { - WLog_DBG(TAG, "performing delayed resize to %dx%d", xfDisp->targetWidth, xfDisp->targetHeight); - xf_disp_sendResize(xfDisp, xfDisp->targetWidth, xfDisp->targetHeight); - } + xf_disp_sendResize(xfDisp); } } static void xf_disp_OnTimer(void* context, TimerEventArgs* e) { - xfContext *xfc = (xfContext *)context; - xfDispContext *xfDisp = xfc->xfDisp; - rdpSettings *settings = xfc->context.settings; + xfContext* xfc; + xfDispContext* xfDisp; + rdpSettings* settings; + + if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings)) + return; if (!xfDisp->activated || settings->Fullscreen) return; - if (e->now - xfDisp->lastSentDate < RESIZE_MIN_DELAY) - return; - - if ((xfDisp->lastSentWidth != xfDisp->targetWidth) || (xfDisp->lastSentHeight != xfDisp->targetHeight)) - { - WLog_DBG(TAG, "timer performing delayed resize to %dx%d", xfDisp->targetWidth, xfDisp->targetHeight); - xf_disp_sendResize(xfDisp, xfDisp->targetWidth, xfDisp->targetHeight); - } + xf_disp_sendResize(xfDisp); } -xfDispContext *xf_disp_new(xfContext* xfc) +xfDispContext* xf_disp_new(xfContext* xfc) { - xfDispContext *ret = calloc(1, sizeof(xfDispContext)); + xfDispContext* ret; + + if (!xfc || !xfc->context.settings || !xfc->context.pubSub) + return NULL; + + ret = calloc(1, sizeof(xfDispContext)); + if (!ret) return NULL; ret->xfc = xfc; #ifdef USABLE_XRANDR + if (XRRQueryExtension(xfc->display, &ret->eventBase, &ret->errorBase)) { ret->haveXRandr = TRUE; } + #endif ret->lastSentWidth = ret->targetWidth = xfc->context.settings->DesktopWidth; ret->lastSentHeight = ret->targetHeight = xfc->context.settings->DesktopHeight; - PubSub_SubscribeActivated(xfc->context.pubSub, xf_disp_OnActivated); PubSub_SubscribeGraphicsReset(xfc->context.pubSub, xf_disp_OnGraphicsReset); PubSub_SubscribeTimer(xfc->context.pubSub, xf_disp_OnTimer); return ret; } -void xf_disp_free(xfDispContext *disp) +void xf_disp_free(xfDispContext* disp) { - PubSub_UnsubscribeActivated(disp->xfc->context.pubSub, xf_disp_OnActivated); - PubSub_UnsubscribeTimer(disp->xfc->context.pubSub, xf_disp_OnTimer); + if (!disp) + return; + + if (disp->xfc) + { + PubSub_UnsubscribeActivated(disp->xfc->context.pubSub, xf_disp_OnActivated); + PubSub_UnsubscribeGraphicsReset(disp->xfc->context.pubSub, xf_disp_OnGraphicsReset); + PubSub_UnsubscribeTimer(disp->xfc->context.pubSub, xf_disp_OnTimer); + } + free(disp); } -static UINT xf_disp_sendLayout(DispClientContext *disp, rdpMonitor *monitors, int nmonitors) +UINT xf_disp_sendLayout(DispClientContext* disp, rdpMonitor* monitors, int nmonitors) { UINT ret = CHANNEL_RC_OK; - DISPLAY_CONTROL_MONITOR_LAYOUT *layouts; + DISPLAY_CONTROL_MONITOR_LAYOUT* layouts; int i; - xfDispContext *xfDisp = (xfDispContext *)disp->custom; - rdpSettings *settings = xfDisp->xfc->context.settings; - + xfDispContext* xfDisp = (xfDispContext*)disp->custom; + rdpSettings* settings = xfDisp->xfc->context.settings; layouts = calloc(nmonitors, sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT)); + if (!layouts) return CHANNEL_RC_NO_MEMORY; @@ -218,89 +309,101 @@ static UINT xf_disp_sendLayout(DispClientContext *disp, rdpMonitor *monitors, in layouts[i].PhysicalWidth = monitors[i].attributes.physicalWidth; layouts[i].PhysicalHeight = monitors[i].attributes.physicalHeight; - switch(monitors[i].attributes.orientation) + switch (monitors[i].attributes.orientation) { - case 90: - layouts[i].Orientation = ORIENTATION_PORTRAIT; - break; - case 180: - layouts[i].Orientation = ORIENTATION_LANDSCAPE_FLIPPED; - break; - case 270: - layouts[i].Orientation = ORIENTATION_PORTRAIT_FLIPPED; - break; - case 0: - default: - /* MS-RDPEDISP - 2.2.2.2.1: - * Orientation (4 bytes): A 32-bit unsigned integer that specifies the - * orientation of the monitor in degrees. Valid values are 0, 90, 180 - * or 270 - * - * So we default to ORIENTATION_LANDSCAPE - */ - layouts[i].Orientation = ORIENTATION_LANDSCAPE; - break; + case 90: + layouts[i].Orientation = ORIENTATION_PORTRAIT; + break; + + case 180: + layouts[i].Orientation = ORIENTATION_LANDSCAPE_FLIPPED; + break; + + case 270: + layouts[i].Orientation = ORIENTATION_PORTRAIT_FLIPPED; + break; + + case 0: + default: + /* MS-RDPEDISP - 2.2.2.2.1: + * Orientation (4 bytes): A 32-bit unsigned integer that specifies the + * orientation of the monitor in degrees. Valid values are 0, 90, 180 + * or 270 + * + * So we default to ORIENTATION_LANDSCAPE + */ + layouts[i].Orientation = ORIENTATION_LANDSCAPE; + break; } + layouts[i].DesktopScaleFactor = settings->DesktopScaleFactor; layouts[i].DeviceScaleFactor = settings->DeviceScaleFactor; } - ret = disp->SendMonitorLayout(disp, nmonitors, layouts); - + ret = IFCALLRESULT(CHANNEL_RC_OK, disp->SendMonitorLayout, disp, nmonitors, layouts); free(layouts); - return ret; } -BOOL xf_disp_handle_xevent(xfContext *xfc, XEvent *event) +BOOL xf_disp_handle_xevent(xfContext* xfc, XEvent* event) { - xfDispContext *xfDisp = xfc->xfDisp; - rdpSettings *settings = xfc->context.settings; + xfDispContext* xfDisp; + rdpSettings* settings; UINT32 maxWidth, maxHeight; - if (!xfDisp->haveXRandr) + if (!xfc || !event) + return FALSE; + + xfDisp = xfc->xfDisp; + + if (!xfDisp) + return FALSE; + + settings = xfc->context.settings; + + if (!settings) + return FALSE; + + if (!xfDisp->haveXRandr || !xfDisp->disp) return TRUE; #ifdef USABLE_XRANDR + if (event->type != xfDisp->eventBase + RRScreenChangeNotify) return TRUE; + #endif - xf_detect_monitors(xfc, &maxWidth, &maxHeight); - return xf_disp_sendLayout(xfc->disp, settings->MonitorDefArray, settings->MonitorCount) == CHANNEL_RC_OK; + return xf_disp_sendLayout(xfDisp->disp, settings->MonitorDefArray, + settings->MonitorCount) == CHANNEL_RC_OK; } - -BOOL xf_disp_handle_configureNotify(xfContext *xfc, int width, int height) +BOOL xf_disp_handle_configureNotify(xfContext* xfc, int width, int height) { - xfDispContext *xfDisp = xfc->xfDisp; + xfDispContext* xfDisp; - if (xfDisp->lastSentWidth == width && xfDisp->lastSentHeight == height) - return TRUE; + if (!xfc) + return FALSE; - if (xfDisp->waitingResize || !xfDisp->activated || - (GetTickCount64() - xfDisp->lastSentDate < RESIZE_MIN_DELAY)) - { - WLog_DBG(TAG, "delaying resize to %dx%d", width, height); - xfDisp->targetWidth = width; - xfDisp->targetHeight = height; - return TRUE; - } + xfDisp = xfc->xfDisp; - WLog_DBG(TAG, "resizing on ConfigureNotify to %dx%d", width, height); - return xf_disp_sendResize(xfDisp, width, height); + if (!xfDisp) + return FALSE; + + xfDisp->targetWidth = width; + xfDisp->targetHeight = height; + return xf_disp_sendResize(xfDisp); } - -UINT xf_DisplayControlCaps(DispClientContext *disp, UINT32 maxNumMonitors, UINT32 maxMonitorAreaFactorA, UINT32 maxMonitorAreaFactorB) +static UINT xf_DisplayControlCaps(DispClientContext* disp, UINT32 maxNumMonitors, + UINT32 maxMonitorAreaFactorA, UINT32 maxMonitorAreaFactorB) { /* we're called only if dynamic resolution update is activated */ - xfDispContext *xfDisp = (xfDispContext *)disp->custom; - rdpSettings *settings = xfDisp->xfc->context.settings; - - WLog_DBG(TAG, "DisplayControlCapsPdu: MaxNumMonitors: %"PRIu32" MaxMonitorAreaFactorA: %"PRIu32" MaxMonitorAreaFactorB: %"PRIu32"", - maxNumMonitors, maxMonitorAreaFactorA, maxMonitorAreaFactorB); - + xfDispContext* xfDisp = (xfDispContext*)disp->custom; + rdpSettings* settings = xfDisp->xfc->context.settings; + WLog_DBG(TAG, + "DisplayControlCapsPdu: MaxNumMonitors: %"PRIu32" MaxMonitorAreaFactorA: %"PRIu32" MaxMonitorAreaFactorB: %"PRIu32"", + maxNumMonitors, maxMonitorAreaFactorA, maxMonitorAreaFactorB); xfDisp->activated = TRUE; if (settings->Fullscreen) @@ -310,24 +413,44 @@ UINT xf_DisplayControlCaps(DispClientContext *disp, UINT32 maxNumMonitors, UINT3 return xf_disp_set_window_resizable(xfDisp) ? CHANNEL_RC_OK : CHANNEL_RC_NO_MEMORY; } -BOOL xf_disp_init(xfContext* xfc, DispClientContext *disp) +BOOL xf_disp_init(xfDispContext* xfDisp, DispClientContext* disp) { - rdpSettings *settings = xfc->context.settings; - xfc->disp = disp; - disp->custom = (void*) xfc->xfDisp; + rdpSettings* settings; + + if (!xfDisp || !xfDisp->xfc || !disp) + return FALSE; + + settings = xfDisp->xfc->context.settings; + + if (!settings) + return FALSE; + + xfDisp->disp = disp; + disp->custom = (void*) xfDisp; if (settings->DynamicResolutionUpdate) { disp->DisplayControlCaps = xf_DisplayControlCaps; #ifdef USABLE_XRANDR + if (settings->Fullscreen) { /* ask X11 to notify us of screen changes */ - XRRSelectInput(xfc->display, DefaultRootWindow(xfc->display), RRScreenChangeNotifyMask); + XRRSelectInput(xfDisp->xfc->display, DefaultRootWindow(xfDisp->xfc->display), + RRScreenChangeNotifyMask); } + #endif } return TRUE; } +BOOL xf_disp_uninit(xfDispContext* xfDisp, DispClientContext* disp) +{ + if (!xfDisp || !disp) + return FALSE; + + xfDisp->disp = NULL; + return TRUE; +} diff --git a/client/X11/xf_disp.h b/client/X11/xf_disp.h index b730e32..6e2db41 100644 --- a/client/X11/xf_disp.h +++ b/client/X11/xf_disp.h @@ -25,12 +25,13 @@ #include "xf_client.h" #include "xfreerdp.h" -FREERDP_API BOOL xf_disp_init(xfContext* xfc, DispClientContext *disp); +FREERDP_API BOOL xf_disp_init(xfDispContext* xfDisp, DispClientContext* disp); +FREERDP_API BOOL xf_disp_uninit(xfDispContext* xfDisp, DispClientContext* disp); -xfDispContext *xf_disp_new(xfContext* xfc); -void xf_disp_free(xfDispContext *disp); -BOOL xf_disp_handle_xevent(xfContext *xfc, XEvent *event); -BOOL xf_disp_handle_configureNotify(xfContext *xfc, int width, int height); -void xf_disp_resized(xfDispContext *disp); +xfDispContext* xf_disp_new(xfContext* xfc); +void xf_disp_free(xfDispContext* disp); +BOOL xf_disp_handle_xevent(xfContext* xfc, XEvent* event); +BOOL xf_disp_handle_configureNotify(xfContext* xfc, int width, int height); +void xf_disp_resized(xfDispContext* disp); #endif /* FREERDP_CLIENT_X11_DISP_H */ diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c index 3dca71e..70c3aee 100644 --- a/client/X11/xf_event.c +++ b/client/X11/xf_event.c @@ -183,6 +183,7 @@ BOOL xf_event_action_script_init(xfContext* xfc) if (!xevent || ArrayList_Add(xfc->xevents, xevent) < 0) { + pclose(actionScript); ArrayList_Free(xfc->xevents); xfc->xevents = NULL; return FALSE; @@ -366,6 +367,9 @@ static BOOL xf_event_MotionNotify(xfContext* xfc, XEvent* event, BOOL app) if (xfc->use_xinput) return TRUE; + if(xfc->floatbar && !(app)) + xf_floatbar_set_root_y(xfc, event->xmotion.y); + return xf_generic_MotionNotify(xfc, event->xmotion.x, event->xmotion.y, event->xmotion.state, event->xmotion.window, app); } @@ -828,6 +832,15 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, XEvent* event, BOOL app) unsigned long nitems; unsigned long bytes; unsigned char* prop; + xfAppWindow* appWindow = NULL; + + if (app) + { + appWindow = xf_AppWindowFromX11Window(xfc, event->xany.window); + + if (!appWindow) + return TRUE; + } if ((Atom) event->xproperty.atom == xfc->_NET_WM_STATE) { @@ -875,12 +888,6 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, XEvent* event, BOOL app) if (app) { - xfAppWindow* appWindow; - appWindow = xf_AppWindowFromX11Window(xfc, event->xany.window); - - if (!appWindow) - return TRUE; - if (maxVert && maxHorz && !minimized && (appWindow->rail_state != WINDOW_SHOW_MAXIMIZED)) { @@ -1011,6 +1018,12 @@ BOOL xf_event_process(freerdp* instance, XEvent* event) } } + if (xfc->floatbar && xf_floatbar_check_event(xfc, event)) + { + xf_floatbar_event_process(xfc, event); + return TRUE; + } + xf_event_execute_action_script(xfc, event); if (event->type != MotionNotify) @@ -1099,7 +1112,7 @@ BOOL xf_event_process(freerdp* instance, XEvent* event) break; default: - if (settings->SupportDisplayControl && xfc->xfDisp) + if (settings->SupportDisplayControl) xf_disp_handle_xevent(xfc, event); break; diff --git a/client/X11/xf_floatbar.c b/client/X11/xf_floatbar.c new file mode 100644 index 0000000..1d60072 --- /dev/null +++ b/client/X11/xf_floatbar.c @@ -0,0 +1,722 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * X11 Windows + * + * Licensed under the Apache License, Version 2.0 (the "License");n + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include "xf_floatbar.h" +#include "resource/close.xbm" +#include "resource/lock.xbm" +#include "resource/unlock.xbm" +#include "resource/minimize.xbm" +#include "resource/restore.xbm" + +#define TAG CLIENT_TAG("x11") + +#define FLOATBAR_HEIGHT 26 +#define FLOATBAR_DEFAULT_WIDTH 576 +#define FLOATBAR_MIN_WIDTH 200 +#define FLOATBAR_BORDER 24 +#define FLOATBAR_BUTTON_WIDTH 24 +#define FLOATBAR_COLOR_BACKGROUND "RGB:31/6c/a9" +#define FLOATBAR_COLOR_BORDER "RGB:75/9a/c8" +#define FLOATBAR_COLOR_FOREGROUND "RGB:FF/FF/FF" + +#ifdef WITH_DEBUG_X11 +#define DEBUG_X11(...) WLog_DBG(TAG, __VA_ARGS__) +#else +#define DEBUG_X11(...) do { } while (0) +#endif + +#define XF_FLOATBAR_MODE_NONE 0 +#define XF_FLOATBAR_MODE_DRAGGING 1 +#define XF_FLOATBAR_MODE_RESIZE_LEFT 2 +#define XF_FLOATBAR_MODE_RESIZE_RIGHT 3 + + +#define XF_FLOATBAR_BUTTON_CLOSE 1 +#define XF_FLOATBAR_BUTTON_RESTORE 2 +#define XF_FLOATBAR_BUTTON_MINIMIZE 3 +#define XF_FLOATBAR_BUTTON_LOCKED 4 + +typedef struct xf_floatbar_button xfFloatbarButton; + +struct xf_floatbar +{ + int x; + int y; + int width; + int height; + int mode; + int last_motion_x_root; + int last_motion_y_root; + bool locked; + xfFloatbarButton* buttons[4]; + Window handle; +}; + +struct xf_floatbar_button +{ + int x; + int y; + int type; + bool focus; + bool clicked; + OnClick onclick; + Window handle; +}; + +static void xf_floatbar_button_onclick_close(xfContext* xfc) +{ + ExitProcess(EXIT_SUCCESS); +} + +static void xf_floatbar_button_onclick_minimize(xfContext* xfc) +{ + xf_SetWindowMinimized(xfc, xfc->window); +} + +static void xf_floatbar_button_onclick_restore(xfContext* xfc) +{ + xf_toggle_fullscreen(xfc); +} + +static void xf_floatbar_button_onclick_locked(xfContext* xfc) +{ + xfFloatbar* floatbar; + floatbar = xfc->window->floatbar; + floatbar->locked = (floatbar->locked) ? FALSE : TRUE; +} + +void xf_floatbar_set_root_y(xfContext* xfc, int y) +{ + xfFloatbar* floatbar; + floatbar = xfc->window->floatbar; + floatbar->last_motion_y_root = y; +} + +void xf_floatbar_hide_and_show(xfContext* xfc) +{ + xfFloatbar* floatbar; + floatbar = xfc->window->floatbar; + + if (!floatbar->locked) + { + if ((floatbar->mode == 0) && (floatbar->last_motion_y_root > 10) && + (floatbar->y > (FLOATBAR_HEIGHT * -1))) + { + floatbar->y = floatbar->y - 1; + XMoveWindow(xfc->display, floatbar->handle, floatbar->x, floatbar->y); + } + else if (floatbar->y < 0 && (floatbar->last_motion_y_root < 10)) + { + floatbar->y = floatbar->y + 1; + XMoveWindow(xfc->display, floatbar->handle, floatbar->x, floatbar->y); + } + } +} + +void xf_floatbar_toggle_visibility(xfContext* xfc, bool visible) +{ + xfFloatbar* floatbar; + int i, size; + floatbar = xfc->window->floatbar; + + if (visible) + { + XMapWindow(xfc->display, floatbar->handle); + size = ARRAYSIZE(floatbar->buttons); + + for (i = 0; i < size; i++) + { + XMapWindow(xfc->display, floatbar->buttons[i]->handle); + } + } + else + { + XUnmapSubwindows(xfc->display, floatbar->handle); + XUnmapWindow(xfc->display, floatbar->handle); + } +} + +static xfFloatbarButton* xf_floatbar_new_button(xfContext* xfc, xfFloatbar* floatbar, int type) +{ + xfFloatbarButton* button; + button = (xfFloatbarButton*) calloc(1, sizeof(xfFloatbarButton)); + button->type = type; + + switch (type) + { + case XF_FLOATBAR_BUTTON_CLOSE: + button->x = floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * type; + button->onclick = xf_floatbar_button_onclick_close; + break; + + case XF_FLOATBAR_BUTTON_RESTORE: + button->x = floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * type; + button->onclick = xf_floatbar_button_onclick_restore; + break; + + case XF_FLOATBAR_BUTTON_MINIMIZE: + button->x = floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * type; + button->onclick = xf_floatbar_button_onclick_minimize; + break; + + case XF_FLOATBAR_BUTTON_LOCKED: + button->x = FLOATBAR_BORDER; + button->onclick = xf_floatbar_button_onclick_locked; + break; + + default: + break; + } + + button->y = 0; + button->focus = FALSE; + button->handle = XCreateWindow(xfc->display, floatbar->handle, button->x, 0, FLOATBAR_BUTTON_WIDTH, + FLOATBAR_BUTTON_WIDTH, 0, CopyFromParent, InputOutput, CopyFromParent, 0, NULL); + XSelectInput(xfc->display, button->handle, ExposureMask | ButtonPressMask | ButtonReleaseMask | + FocusChangeMask | LeaveWindowMask | EnterWindowMask | StructureNotifyMask); + return button; +} + +xfFloatbar* xf_floatbar_new(xfContext* xfc, Window window) +{ + xfFloatbar* floatbar; + XWindowAttributes attr; + int i, width; + if (!xfc) + return NULL; + + floatbar = (xfFloatbar*) calloc(1, sizeof(xfFloatbar)); + floatbar->locked = TRUE; + XGetWindowAttributes(xfc->display, window, &attr); + + for (i = 0; i < xfc->vscreen.nmonitors; i++) + { + if (attr.x >= xfc->vscreen.monitors[i].area.left && attr.x <= xfc->vscreen.monitors[i].area.right) + { + width = xfc->vscreen.monitors[i].area.right - xfc->vscreen.monitors[i].area.left; + floatbar->x = width / 2 + xfc->vscreen.monitors[i].area.left - FLOATBAR_DEFAULT_WIDTH / 2; + } + } + + floatbar->y = 0; + floatbar->handle = XCreateWindow(xfc->display, window, floatbar->x, 0, FLOATBAR_DEFAULT_WIDTH, + FLOATBAR_HEIGHT, 0, + CopyFromParent, InputOutput, CopyFromParent, 0, NULL); + floatbar->width = FLOATBAR_DEFAULT_WIDTH; + floatbar->height = FLOATBAR_HEIGHT; + floatbar->mode = XF_FLOATBAR_MODE_NONE; + floatbar->buttons[0] = xf_floatbar_new_button(xfc, floatbar, XF_FLOATBAR_BUTTON_CLOSE); + floatbar->buttons[1] = xf_floatbar_new_button(xfc, floatbar, XF_FLOATBAR_BUTTON_RESTORE); + floatbar->buttons[2] = xf_floatbar_new_button(xfc, floatbar, XF_FLOATBAR_BUTTON_MINIMIZE); + floatbar->buttons[3] = xf_floatbar_new_button(xfc, floatbar, XF_FLOATBAR_BUTTON_LOCKED); + XSelectInput(xfc->display, floatbar->handle, ExposureMask | ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | FocusChangeMask | LeaveWindowMask | EnterWindowMask | StructureNotifyMask | + PropertyChangeMask); + return floatbar; +} + +static unsigned long xf_floatbar_get_color(xfContext* xfc, char* rgb_value) +{ + Colormap cmap; + XColor color; + cmap = DefaultColormap(xfc->display, XDefaultScreen(xfc->display)); + XParseColor(xfc->display, cmap, rgb_value, &color); + XAllocColor(xfc->display, cmap, &color); + XFreeColormap(xfc->display, cmap); + return color.pixel; +} + +static void xf_floatbar_event_expose(xfContext* xfc, XEvent* event) +{ + GC gc, shape_gc; + Pixmap pmap; + XPoint shape[5], border[5]; + xfFloatbar* floatbar; + int len; + floatbar = xfc->window->floatbar; + /* create the pixmap that we'll use for shaping the window */ + pmap = XCreatePixmap(xfc->display, floatbar->handle, floatbar->width, floatbar->height, 1); + gc = XCreateGC(xfc->display, floatbar->handle, 0, 0); + shape_gc = XCreateGC(xfc->display, pmap, 0, 0); + /* points for drawing the floatbar */ + shape[0].x = 0; + shape[0].y = 0; + shape[1].x = floatbar->width; + shape[1].y = 0; + shape[2].x = shape[1].x - FLOATBAR_BORDER; + shape[2].y = FLOATBAR_HEIGHT; + shape[3].x = shape[0].x + FLOATBAR_BORDER; + shape[3].y = FLOATBAR_HEIGHT; + shape[4].x = shape[0].x; + shape[4].y = shape[0].y; + /* points for drawing the border of the floatbar */ + border[0].x = shape[0].x; + border[0].y = shape[0].y - 1; + border[1].x = shape[1].x - 1; + border[1].y = shape[1].y - 1; + border[2].x = shape[2].x; + border[2].y = shape[2].y - 1; + border[3].x = shape[3].x - 1; + border[3].y = shape[3].y - 1; + border[4].x = border[0].x; + border[4].y = border[0].y; + /* Fill all pixels with 0 */ + XSetForeground(xfc->display, shape_gc, 0); + XFillRectangle(xfc->display, pmap, shape_gc, 0, 0, floatbar->width, + floatbar->height); + /* Fill all pixels which should be shown with 1 */ + XSetForeground(xfc->display, shape_gc, 1); + XFillPolygon(xfc->display, pmap, shape_gc, shape, 5, 0, CoordModeOrigin); + XShapeCombineMask(xfc->display, floatbar->handle, ShapeBounding, 0, 0, pmap, ShapeSet); + /* draw the float bar */ + XSetForeground(xfc->display, gc, xf_floatbar_get_color(xfc, FLOATBAR_COLOR_BACKGROUND)); + XFillPolygon(xfc->display, floatbar->handle, gc, shape, 4, 0, CoordModeOrigin); + /* draw an border for the floatbar */ + XSetForeground(xfc->display, gc, xf_floatbar_get_color(xfc, FLOATBAR_COLOR_BORDER)); + XDrawLines(xfc->display, floatbar->handle, gc, border, 5, CoordModeOrigin); + /* draw the host name connected to */ + len = strlen(xfc->context.settings->ServerHostname); + XSetForeground(xfc->display, gc, xf_floatbar_get_color(xfc, FLOATBAR_COLOR_FOREGROUND)); + XDrawString(xfc->display, floatbar->handle, gc, floatbar->width / 2 - len * 2, 15, + xfc->context.settings->ServerHostname, len); + XFreeGC(xfc->display, gc); + XFreeGC(xfc->display, shape_gc); +} + +static xfFloatbarButton* xf_floatbar_get_button(xfContext* xfc, XEvent* event) +{ + xfFloatbar* floatbar; + int i, size; + size = ARRAYSIZE(floatbar->buttons); + floatbar = xfc->window->floatbar; + + for (i = 0; i < size; i++) + { + if (floatbar->buttons[i]->handle == event->xany.window) + { + return floatbar->buttons[i]; + } + } + + return NULL; +} + +static void xf_floatbar_button_update_positon(xfContext* xfc, XEvent* event) +{ + xfFloatbar* floatbar; + xfFloatbarButton* button; + int i, size; + floatbar = xfc->window->floatbar; + size = ARRAYSIZE(floatbar->buttons); + + for (i = 0; i < size; i++) + { + button = floatbar->buttons[i]; + + switch (button->type) + { + case XF_FLOATBAR_BUTTON_CLOSE: + button->x = floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type; + break; + + case XF_FLOATBAR_BUTTON_RESTORE: + button->x = floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type; + break; + + case XF_FLOATBAR_BUTTON_MINIMIZE: + button->x = floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type; + break; + + default: + break; + } + + XMoveWindow(xfc->display, button->handle, button->x, button->y); + xf_floatbar_event_expose(xfc, event); + } +} + +static void xf_floatbar_button_event_expose(xfContext* xfc, XEvent* event) +{ + xfFloatbar* floatbar; + xfFloatbarButton* button; + static unsigned char* bits; + GC gc; + Pixmap pattern; + button = xf_floatbar_get_button(xfc, event); + + if (!button) + return; + + gc = XCreateGC(xfc->display, button->handle, 0, 0); + floatbar = xfc->window->floatbar; + + switch (button->type) + { + case XF_FLOATBAR_BUTTON_CLOSE: + bits = close_bits; + break; + + case XF_FLOATBAR_BUTTON_RESTORE: + bits = restore_bits; + break; + + case XF_FLOATBAR_BUTTON_MINIMIZE: + bits = minimize_bits; + break; + + case XF_FLOATBAR_BUTTON_LOCKED: + if (floatbar->locked) + bits = lock_bits; + else + bits = unlock_bits; + + break; + + default: + break; + } + + pattern = XCreateBitmapFromData(xfc->display, button->handle, (const char*)bits, + FLOATBAR_BUTTON_WIDTH, FLOATBAR_BUTTON_WIDTH); + + if (!(button->focus)) + XSetForeground(xfc->display, gc, xf_floatbar_get_color(xfc, FLOATBAR_COLOR_BACKGROUND)); + else + XSetForeground(xfc->display, gc, xf_floatbar_get_color(xfc, FLOATBAR_COLOR_BORDER)); + + XSetBackground(xfc->display, gc, xf_floatbar_get_color(xfc, FLOATBAR_COLOR_FOREGROUND)); + XCopyPlane(xfc->display, pattern, button->handle, gc, 0, 0, FLOATBAR_BUTTON_WIDTH, + FLOATBAR_BUTTON_WIDTH, 0, 0, 1); + XFreePixmap(xfc->display, pattern); + XFreeGC(xfc->display, gc); +} + +static void xf_floatbar_button_event_buttonpress(xfContext* xfc, XEvent* event) +{ + xfFloatbarButton* button; + button = xf_floatbar_get_button(xfc, event); + + if (button) + button->clicked = TRUE; +} + +static void xf_floatbar_button_event_buttonrelease(xfContext* xfc, XEvent* event) +{ + xfFloatbarButton* button; + button = xf_floatbar_get_button(xfc, event); + + if (button) + { + if (button->clicked) + button->onclick(xfc); + } +} + +static void xf_floatbar_event_buttonpress(xfContext* xfc, XEvent* event) +{ + xfFloatbar* floatbar; + floatbar = xfc->window->floatbar; + + switch (event->xbutton.button) + { + case Button1: + if (event->xmotion.x <= FLOATBAR_BORDER) + floatbar->mode = XF_FLOATBAR_MODE_RESIZE_LEFT; + else if (event->xmotion.x >= (floatbar->width - FLOATBAR_BORDER)) + floatbar->mode = XF_FLOATBAR_MODE_RESIZE_RIGHT; + else + floatbar->mode = XF_FLOATBAR_MODE_DRAGGING; + + break; + + default: + break; + } +} + +static void xf_floatbar_event_buttonrelease(xfContext* xfc, XEvent* event) +{ + switch (event->xbutton.button) + { + case Button1: + xfc->window->floatbar->mode = XF_FLOATBAR_MODE_NONE; + break; + + default: + break; + } +} + +static void xf_floatbar_resize(xfContext* xfc, XEvent* event) +{ + xfFloatbar* floatbar; + floatbar = xfc->window->floatbar; + int x, width, movement; + /* calculate movement which happened on the root window */ + movement = event->xmotion.x_root - floatbar->last_motion_x_root; + + /* set x and width depending if movement happens on the left or right */ + if (floatbar->mode == XF_FLOATBAR_MODE_RESIZE_LEFT) + { + x = floatbar->x + movement; + width = floatbar->width + movement * -1; + } + else + { + x = floatbar->x; + width = floatbar->width + movement; + } + + /* only resize and move window if still above minimum width */ + if (FLOATBAR_MIN_WIDTH < width) + { + XMoveResizeWindow(xfc->display, floatbar->handle, x, 0, width, floatbar->height); + floatbar->x = x; + floatbar->width = width; + } +} + +static void xf_floatbar_dragging(xfContext* xfc, XEvent* event) +{ + xfFloatbar* floatbar; + floatbar = xfc->window->floatbar; + int x, movement; + /* calculate movement and new x position */ + movement = event->xmotion.x_root - floatbar->last_motion_x_root; + x = floatbar->x + movement; + + /* do nothing if floatbar would be moved out of the window */ + if (x < 0 || (x + floatbar->width) > xfc->window->width) + return; + + /* move window to new x position */ + XMoveWindow(xfc->display, floatbar->handle, x, 0); + /* update struct values for the next event */ + floatbar->last_motion_x_root = floatbar->last_motion_x_root + movement; + floatbar->x = x; +} + +static void xf_floatbar_event_motionnotify(xfContext* xfc, XEvent* event) +{ + int mode; + xfFloatbar* floatbar; + Cursor cursor; + mode = xfc->window->floatbar->mode; + floatbar = xfc->window->floatbar; + cursor = XCreateFontCursor(xfc->display, XC_arrow); + + if ((event->xmotion.state & Button1Mask) && (mode > XF_FLOATBAR_MODE_DRAGGING)) + { + xf_floatbar_resize(xfc, event); + } + else if ((event->xmotion.state & Button1Mask) && (mode == XF_FLOATBAR_MODE_DRAGGING)) + { + xf_floatbar_dragging(xfc, event); + } + else + { + if (event->xmotion.x <= FLOATBAR_BORDER || + event->xmotion.x >= xfc->window->floatbar->width - FLOATBAR_BORDER) + cursor = XCreateFontCursor(xfc->display, XC_sb_h_double_arrow); + } + + XDefineCursor(xfc->display, xfc->window->handle, cursor); + XFreeCursor(xfc->display, cursor); + xfc->window->floatbar->last_motion_x_root = event->xmotion.x_root; +} + +static void xf_floatbar_button_event_focusin(xfContext* xfc, XEvent* event) +{ + xfFloatbarButton* button; + button = xf_floatbar_get_button(xfc, event); + + if (button) + { + button->focus = TRUE; + xf_floatbar_button_event_expose(xfc, event); + } +} + +static void xf_floatbar_button_event_focusout(xfContext* xfc, XEvent* event) +{ + xfFloatbarButton* button; + button = xf_floatbar_get_button(xfc, event); + + if (button) + { + button->focus = FALSE; + button->clicked = FALSE; + xf_floatbar_button_event_expose(xfc, event); + } +} + +static void xf_floatbar_event_focusout(xfContext* xfc, XEvent* event) +{ + Cursor cursor; + cursor = XCreateFontCursor(xfc->display, XC_arrow); + XDefineCursor(xfc->display, xfc->window->handle, cursor); + XFreeCursor(xfc->display, cursor); +} + +BOOL xf_floatbar_check_event(xfContext* xfc, XEvent* event) +{ + xfFloatbar* floatbar; + xfFloatbarButton* button; + size_t i, size; + + if (!xfc || !event || !xfc->window) + return FALSE; + + floatbar = xfc->window->floatbar; + + if (event->xany.window == floatbar->handle) + return TRUE; + + size = ARRAYSIZE(floatbar->buttons); + + for (i = 0; i < size; i++) + { + button = floatbar->buttons[i]; + + if (event->xany.window == button->handle) + return TRUE; + } + + return FALSE; +} + +BOOL xf_floatbar_event_process(xfContext* xfc, XEvent* event) +{ + xfFloatbar* floatbar; + + if (!xfc || !xfc->window || !event) + return FALSE; + + floatbar = xfc->window->floatbar; + + switch (event->type) + { + case Expose: + if (event->xany.window == floatbar->handle) + xf_floatbar_event_expose(xfc, event); + else + xf_floatbar_button_event_expose(xfc, event); + + break; + + case MotionNotify: + xf_floatbar_event_motionnotify(xfc, event); + break; + + case ButtonPress: + if (event->xany.window == floatbar->handle) + xf_floatbar_event_buttonpress(xfc, event); + else + xf_floatbar_button_event_buttonpress(xfc, event); + + break; + + case ButtonRelease: + if (event->xany.window == floatbar->handle) + xf_floatbar_event_buttonrelease(xfc, event); + else + xf_floatbar_button_event_buttonrelease(xfc, event); + + break; + + case EnterNotify: + case FocusIn: + if (event->xany.window != floatbar->handle) + xf_floatbar_button_event_focusin(xfc, event); + + break; + + case LeaveNotify: + case FocusOut: + if (event->xany.window == floatbar->handle) + xf_floatbar_event_focusout(xfc, event); + else + xf_floatbar_button_event_focusout(xfc, event); + + break; + + case ConfigureNotify: + if (event->xany.window == floatbar->handle) + xf_floatbar_button_update_positon(xfc, event); + + break; + + case PropertyNotify: + if (event->xany.window == floatbar->handle) + xf_floatbar_button_update_positon(xfc, event); + + break; + + default: + break; + } + + return floatbar->handle == event->xany.window; +} + +static void xf_floatbar_button_free(xfContext* xfc, xfFloatbarButton* button) +{ + if (!button) + return; + + if (button->handle) + { + XUnmapWindow(xfc->display, button->handle); + XDestroyWindow(xfc->display, button->handle); + } + + free(button); +} + +void xf_floatbar_free(xfContext* xfc, xfWindow* window, xfFloatbar* floatbar) +{ + size_t i, size; + size = ARRAYSIZE(floatbar->buttons); + + if (!floatbar) + return; + + if (window->floatbar == floatbar) + window->floatbar = NULL; + + for (i = 0; i < size; i++) + { + xf_floatbar_button_free(xfc, floatbar->buttons[i]); + floatbar->buttons[i] = NULL; + } + + if (floatbar->handle) + { + XUnmapWindow(xfc->display, floatbar->handle); + XDestroyWindow(xfc->display, floatbar->handle); + } + + free(floatbar); +} diff --git a/client/X11/xf_floatbar.h b/client/X11/xf_floatbar.h new file mode 100644 index 0000000..fecb5cb --- /dev/null +++ b/client/X11/xf_floatbar.h @@ -0,0 +1,34 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * X11 Windows + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CLIENT_X11_FLOATBAR_H +#define FREERDP_CLIENT_X11_FLOATBAR_H + +typedef struct xf_floatbar xfFloatbar; + +#include "xfreerdp.h" + +typedef void(*OnClick)(xfContext*); +xfFloatbar* xf_floatbar_new(xfContext* xfc, Window window); +BOOL xf_floatbar_event_process(xfContext* xfc, XEvent* event); +BOOL xf_floatbar_check_event(xfContext* xfc, XEvent* event); +void xf_floatbar_toggle_visibility(xfContext* xfc, bool visible); +void xf_floatbar_free(xfContext* xfc, xfWindow* window, xfFloatbar* floatbar); +void xf_floatbar_hide_and_show(xfContext* xfc); +void xf_floatbar_set_root_y(xfContext* xfc, int y); + +#endif /* FREERDP_CLIENT_X11_FLOATBAR_H */ diff --git a/client/X11/xf_gdi.c b/client/X11/xf_gdi.c index be255d0..8b31d74 100644 --- a/client/X11/xf_gdi.c +++ b/client/X11/xf_gdi.c @@ -245,7 +245,6 @@ static Pixmap xf_brush_new(xfContext* xfc, UINT32 width, UINT32 height, image->bitmap_bit_order = LSBFirst; gc = XCreateGC(xfc->display, xfc->drawable, 0, NULL); XPutImage(xfc->display, bitmap, gc, image, 0, 0, 0, 0, width, height); - image->data = NULL; XDestroyImage(image); @@ -577,7 +576,7 @@ static BOOL xf_gdi_invalidate_poly_region(xfContext* xfc, XPoint* points, static BOOL xf_gdi_polyline(rdpContext* context, const POLYLINE_ORDER* polyline) { - int i; + UINT32 i; int npoints; XColor color; XPoint* points; @@ -1011,6 +1010,7 @@ static BOOL xf_gdi_update_screen(xfContext* xfc, const BYTE* pSrcData, bpp = 2; else bpp = 1; + XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFillStyle(xfc->display, xfc->gc, FillSolid); @@ -1021,15 +1021,14 @@ static BOOL xf_gdi_update_screen(xfContext* xfc, const BYTE* pSrcData, UINT32 width = rects[i].right - rects[i].left; UINT32 height = rects[i].bottom - rects[i].top; const BYTE* src = pSrcData + top * scanline + bpp * left; - image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, (char*) src, width, height, xfc->scanline_pad, scanline); + if (!image) break; image->byte_order = LSBFirst; image->bitmap_bit_order = LSBFirst; - XPutImage(xfc->display, xfc->primary, xfc->gc, image, 0, 0, left, top, width, height); image->data = NULL; XDestroyImage(image); @@ -1059,17 +1058,14 @@ static BOOL xf_gdi_surface_bits(rdpContext* context, cmdRect.top = cmd->destTop; cmdRect.right = cmdRect.left + cmd->bmp.width; cmdRect.bottom = cmdRect.top + cmd->bmp.height; - - gdi = context->gdi; - xf_lock_x11(xfc, FALSE); switch (cmd->bmp.codecID) { case RDP_CODEC_ID_REMOTEFX: if (!rfx_process_message(context->codecs->rfx, cmd->bmp.bitmapData, - cmd->bmp.bitmapDataLength, cmd->destLeft, cmd->destTop, + cmd->bmp.bitmapDataLength, cmd->destLeft, cmd->destTop, gdi->primary_buffer, gdi->dstFormat, gdi->stride, gdi->height, ®ion)) goto fail; @@ -1078,9 +1074,9 @@ static BOOL xf_gdi_surface_bits(rdpContext* context, case RDP_CODEC_ID_NSCODEC: if (!nsc_process_message(context->codecs->nsc, cmd->bmp.bpp, cmd->bmp.width, - cmd->bmp.height, cmd->bmp.bitmapData, cmd->bmp.bitmapDataLength, + cmd->bmp.height, cmd->bmp.bitmapData, cmd->bmp.bitmapDataLength, gdi->primary_buffer, gdi->dstFormat, gdi->stride, - 0, 0, cmd->bmp.width, cmd->bmp.height, FREERDP_FLIP_VERTICAL)) + 0, 0, cmd->bmp.width, cmd->bmp.height, FREERDP_FLIP_VERTICAL)) goto fail; region16_union_rect(®ion, ®ion, &cmdRect); @@ -1091,7 +1087,7 @@ static BOOL xf_gdi_surface_bits(rdpContext* context, format = gdi_get_pixel_format(cmd->bmp.bpp); if (!freerdp_image_copy(gdi->primary_buffer, gdi->dstFormat, gdi->stride, - cmd->destLeft, cmd->destTop, cmd->bmp.width, cmd->bmp.height, + cmd->destLeft, cmd->destTop, cmd->bmp.width, cmd->bmp.height, pSrcData, format, 0, 0, 0, &xfc->context.gdi->palette, FREERDP_FLIP_VERTICAL)) goto fail; diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index 58453af..5efc3f8 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -144,12 +144,12 @@ static BOOL xf_Bitmap_New(rdpContext* context, rdpBitmap* bitmap) xbitmap->image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, (char*) bitmap->data, bitmap->width, bitmap->height, xfc->scanline_pad, 0); + if (!xbitmap->image) goto unlock; xbitmap->image->byte_order = LSBFirst; xbitmap->image->bitmap_bit_order = LSBFirst; - XPutImage(xfc->display, xbitmap->pixmap, xfc->gc, xbitmap->image, 0, 0, 0, 0, bitmap->width, bitmap->height); } @@ -425,8 +425,8 @@ static void xf_Glyph_Free(rdpContext* context, rdpGlyph* glyph) free(glyph); } -static BOOL xf_Glyph_Draw(rdpContext* context, const rdpGlyph* glyph, UINT32 x, - UINT32 y, UINT32 w, UINT32 h, UINT32 sx, UINT32 sy, +static BOOL xf_Glyph_Draw(rdpContext* context, const rdpGlyph* glyph, INT32 x, + INT32 y, INT32 w, INT32 h, INT32 sx, INT32 sy, BOOL fOpRedundant) { xfGlyph* xf_glyph; @@ -453,8 +453,8 @@ static BOOL xf_Glyph_Draw(rdpContext* context, const rdpGlyph* glyph, UINT32 x, return TRUE; } -static BOOL xf_Glyph_BeginDraw(rdpContext* context, UINT32 x, UINT32 y, - UINT32 width, UINT32 height, UINT32 bgcolor, +static BOOL xf_Glyph_BeginDraw(rdpContext* context, INT32 x, INT32 y, + INT32 width, INT32 height, UINT32 bgcolor, UINT32 fgcolor, BOOL fOpRedundant) { xfContext* xfc = (xfContext*) context; @@ -487,8 +487,8 @@ static BOOL xf_Glyph_BeginDraw(rdpContext* context, UINT32 x, UINT32 y, return TRUE; } -static BOOL xf_Glyph_EndDraw(rdpContext* context, UINT32 x, UINT32 y, - UINT32 width, UINT32 height, +static BOOL xf_Glyph_EndDraw(rdpContext* context, INT32 x, INT32 y, + INT32 width, INT32 height, UINT32 bgcolor, UINT32 fgcolor) { xfContext* xfc = (xfContext*) context; diff --git a/client/X11/xf_keyboard.c b/client/X11/xf_keyboard.c index 1eb63e5..61bf89f 100644 --- a/client/X11/xf_keyboard.c +++ b/client/X11/xf_keyboard.c @@ -160,7 +160,7 @@ void xf_keyboard_key_release(xfContext* xfc, BYTE keycode, KeySym keysym) void xf_keyboard_release_all_keypress(xfContext* xfc) { - int keycode; + size_t keycode; DWORD rdp_scancode; for (keycode = 0; keycode < ARRAYSIZE(xfc->KeyboardState); keycode++) @@ -317,6 +317,26 @@ UINT32 xf_keyboard_get_toggle_keys_state(xfContext* xfc) return toggleKeysState; } +static void xk_keyboard_update_modifier_keys(xfContext* xfc) +{ + int state; + size_t i; + KeyCode keycode; + int keysyms[] = {XK_Shift_L, XK_Shift_R, XK_Alt_L, XK_Alt_R, + XK_Control_L, XK_Control_R, XK_Super_L, XK_Super_R + }; + state = xf_keyboard_read_keyboard_state(xfc); + + for (i = 0; i < ARRAYSIZE(keysyms); i++) + { + if (xf_keyboard_get_key_state(xfc, state, keysyms[i])) + { + keycode = XKeysymToKeycode(xfc->display, keysyms[i]); + xfc->KeyboardState[keycode] = TRUE; + } + } +} + void xf_keyboard_focus_in(xfContext* xfc) { rdpInput* input; @@ -330,6 +350,7 @@ void xf_keyboard_focus_in(xfContext* xfc) input = xfc->context.input; syncFlags = xf_keyboard_get_toggle_keys_state(xfc); input->FocusInEvent(input, syncFlags); + xk_keyboard_update_modifier_keys(xfc); /* finish with a mouse pointer position like mstsc.exe if required */ @@ -359,7 +380,7 @@ static int xf_keyboard_execute_action_script(xfContext* xfc, BOOL match = FALSE; char* keyCombination; char buffer[1024] = { 0 }; - char command[1024] = { 0 }; + char command[2048] = { 0 }; char combination[1024] = { 0 }; if (!xfc->actionScriptExists) @@ -388,6 +409,9 @@ static int xf_keyboard_execute_action_script(xfContext* xfc, if (mod->Alt) strcat(combination, "Alt+"); + if (mod->Super) + strcat(combination, "Super+"); + strcat(combination, keyStr); count = ArrayList_Count(xfc->keyCombinations); @@ -447,7 +471,6 @@ BOOL xf_keyboard_handle_special_keys(xfContext* xfc, KeySym keysym) { XF_MODIFIER_KEYS mod = { 0 }; xk_keyboard_get_modifier_keys(xfc, &mod); - rdpContext* ctx = &xfc->context; // remember state of RightCtrl to ungrab keyboard if next action is release of RightCtrl // do not return anything such that the key could be used by client if ungrab is not the goal @@ -500,6 +523,8 @@ BOOL xf_keyboard_handle_special_keys(xfContext* xfc, KeySym keysym) if (!xfc->remote_app && xfc->settings->MultiTouchGestures) { + rdpContext* ctx = &xfc->context; + if (mod.Ctrl && mod.Alt) { int pdx = 0; @@ -597,6 +622,7 @@ void xf_keyboard_handle_special_keys_release(xfContext* xfc, KeySym keysym) xf_toggle_control(xfc); } + xfc->mouse_active = FALSE; XUngrabKeyboard(xfc->display, CurrentTime); } diff --git a/client/X11/xf_monitor.c b/client/X11/xf_monitor.c index d2d3f07..9eb854e 100644 --- a/client/X11/xf_monitor.c +++ b/client/X11/xf_monitor.c @@ -136,7 +136,7 @@ static BOOL xf_is_monitor_id_active(xfContext* xfc, UINT32 id) BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) { - int i; + UINT32 i; int nmonitors = 0; int monitor_index = 0; BOOL primaryMonitorFound = FALSE; @@ -146,6 +146,7 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) Window _dummy_w; int current_monitor = 0; Screen* screen; + MONITOR_INFO* monitor; #if defined WITH_XINERAMA || defined WITH_XRANDR int major, minor; #endif @@ -208,13 +209,6 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) vscreen->monitors[i].area.top = screenInfo[i].y_org; vscreen->monitors[i].area.right = screenInfo[i].x_org + screenInfo[i].width - 1; vscreen->monitors[i].area.bottom = screenInfo[i].y_org + screenInfo[i].height - 1; - - /* Determine which monitor that the mouse cursor is on */ - if ((mouse_x >= vscreen->monitors[i].area.left) && - (mouse_x <= vscreen->monitors[i].area.right) && - (mouse_y >= vscreen->monitors[i].area.top) && - (mouse_y <= vscreen->monitors[i].area.bottom)) - current_monitor = i; } } @@ -225,6 +219,46 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) xfc->fullscreenMonitors.top = xfc->fullscreenMonitors.bottom = xfc->fullscreenMonitors.left = xfc->fullscreenMonitors.right = 0; + /* Determine which monitor that the mouse cursor is on */ + if (vscreen->monitors) + { + for (i = 0; i < vscreen->nmonitors; i++) + { + if ((mouse_x >= vscreen->monitors[i].area.left) && + (mouse_x <= vscreen->monitors[i].area.right) && + (mouse_y >= vscreen->monitors[i].area.top) && + (mouse_y <= vscreen->monitors[i].area.bottom)) + { + current_monitor = i; + break; + } + } + } + + /* + Even for a single monitor, we need to calculate the virtual screen to support + window managers that do not implement all X window state hints. + + If the user did not request multiple monitor or is using workarea + without remote app, we force the number of monitors be 1 so later + the rest of the client don't end up using more monitors than the user desires. + */ + if ((!settings->UseMultimon && !settings->SpanMonitors) || + (settings->Workarea && !settings->RemoteApplicationMode)) + { + /* If no monitors were specified on the command-line then set the current monitor as active */ + if (!settings->NumMonitorIds) + { + settings->MonitorIds[0] = current_monitor; + } + + /* Always sets number of monitors from command-line to just 1. + * If the monitor is invalid then we will default back to current monitor + * later as a fallback. So, there is no need to validate command-line entry here. + */ + settings->NumMonitorIds = 1; + } + /* WORKAROUND: With Remote Application Mode - using NET_WM_WORKAREA * causes issues with the ability to fully size the window vertically * (the bottom of the window area is never updated). So, we just set @@ -232,10 +266,26 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) */ if (settings->RemoteApplicationMode || !xf_GetWorkArea(xfc)) { - xfc->workArea.x = 0; - xfc->workArea.y = 0; - xfc->workArea.width = WidthOfScreen(xfc->screen); - xfc->workArea.height = HeightOfScreen(xfc->screen); + /* + if only 1 monitor is enabled, use monitor area + this is required in case of a screen composed of more than one monitor + but user did not enable multimonitor + */ + if (settings->NumMonitorIds == 1) + { + monitor = vscreen->monitors + current_monitor; + xfc->workArea.x = monitor->area.left; + xfc->workArea.y = monitor->area.top; + xfc->workArea.width = monitor->area.right - monitor->area.left + 1; + xfc->workArea.height = monitor->area.bottom - monitor->area.top + 1; + } + else + { + xfc->workArea.x = 0; + xfc->workArea.y = 0; + xfc->workArea.width = WidthOfScreen(xfc->screen); + xfc->workArea.height = HeightOfScreen(xfc->screen); + } } if (settings->Fullscreen) @@ -288,26 +338,6 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) *pMaxHeight = settings->DesktopHeight; } - if (!settings->Fullscreen && !settings->Workarea && !settings->UseMultimon) - goto out; - - /* If single monitor fullscreen OR workarea without remote app */ - if ((settings->Fullscreen && !settings->UseMultimon && !settings->SpanMonitors) || - (settings->Workarea && !settings->RemoteApplicationMode)) - { - /* If no monitors were specified on the command-line then set the current monitor as active */ - if (!settings->NumMonitorIds) - { - settings->MonitorIds[0] = current_monitor; - } - - /* Always sets number of monitors from command-line to just 1. - * If the monitor is invalid then we will default back to current monitor - * later as a fallback. So, there is no need to validate command-line entry here. - */ - settings->NumMonitorIds = 1; - } - /* Create array of all active monitors by taking into account monitors requested on the command-line */ for (i = 0; i < vscreen->nmonitors; i++) { @@ -340,6 +370,8 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) if (i == settings->MonitorIds[0]) { settings->MonitorDefArray[nmonitors].is_primary = TRUE; + settings->MonitorLocalShiftX = settings->MonitorDefArray[nmonitors].x; + settings->MonitorLocalShiftY = settings->MonitorDefArray[nmonitors].y; primaryMonitorFound = TRUE; } @@ -406,8 +438,6 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) vB = destB; } - settings->DesktopPosX = vX; - settings->DesktopPosY = vY; vscreen->area.left = 0; vscreen->area.right = vR - vX - 1; vscreen->area.top = 0; @@ -489,7 +519,6 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) if (settings->MonitorCount) settings->SupportMonitorLayoutPdu = TRUE; -out: #ifdef USABLE_XRANDR if (rrmonitors) diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c index 61be3e4..0b4e992 100644 --- a/client/X11/xf_rail.c +++ b/client/X11/xf_rail.c @@ -22,6 +22,7 @@ #endif #include +#include #include #include @@ -61,6 +62,22 @@ static const char* movetype_names[] = }; #endif +struct xf_rail_icon +{ + long* data; + int length; +}; +typedef struct xf_rail_icon xfRailIcon; + +struct xf_rail_icon_cache +{ + xfRailIcon* entries; + UINT32 numCaches; + UINT32 numCacheEntries; + xfRailIcon scratch; +}; +typedef struct xf_rail_icon_cache xfRailIconCache; + void xf_rail_enable_remoteapp_mode(xfContext* xfc) { if (!xfc->remote_app) @@ -91,6 +108,11 @@ void xf_rail_send_activate(xfContext* xfc, Window xwindow, BOOL enabled) if (!appWindow) return; + if (enabled) + xf_SetWindowStyle(xfc, appWindow, appWindow->dwStyle, appWindow->dwExStyle); + else + xf_SetWindowStyle(xfc, appWindow, 0, 0); + activate.windowId = appWindow->windowId; activate.enabled = enabled; xfc->rail->ClientActivate(xfc->rail, &activate); @@ -195,7 +217,6 @@ static void xf_rail_invalidate_region(xfContext* xfc, REGION16* invalidRegion) xfAppWindow* appWindow; const RECTANGLE_16* extents; REGION16 windowInvalidRegion; - region16_init(&windowInvalidRegion); count = HashTable_GetKeys(xfc->railWindows, &pKeys); @@ -527,22 +548,332 @@ static BOOL xf_rail_window_delete(rdpContext* context, return TRUE; } +static xfRailIconCache* RailIconCache_New(rdpSettings* settings) +{ + xfRailIconCache* cache; + cache = calloc(1, sizeof(xfRailIconCache)); + + if (!cache) + return NULL; + + cache->numCaches = settings->RemoteAppNumIconCaches; + cache->numCacheEntries = settings->RemoteAppNumIconCacheEntries; + cache->entries = calloc(cache->numCaches * cache->numCacheEntries, + sizeof(xfRailIcon)); + + if (!cache->entries) + { + WLog_ERR(TAG, "failed to allocate icon cache %d x %d entries", + cache->numCaches, cache->numCacheEntries); + free(cache); + return NULL; + } + + return cache; +} + +static void RailIconCache_Free(xfRailIconCache* cache) +{ + UINT32 i; + + if (cache) + { + for (i = 0; i < cache->numCaches * cache->numCacheEntries; i++) + { + free(cache->entries[i].data); + } + + free(cache->scratch.data); + free(cache->entries); + free(cache); + } +} + +static xfRailIcon* RailIconCache_Lookup(xfRailIconCache* cache, + UINT8 cacheId, UINT16 cacheEntry) +{ + /* + * MS-RDPERP 2.2.1.2.3 Icon Info (TS_ICON_INFO) + * + * CacheId (1 byte): + * If the value is 0xFFFF, the icon SHOULD NOT be cached. + * + * Yes, the spec says "0xFFFF" in the 2018-03-16 revision, + * but the actual protocol field is 1-byte wide. + */ + if (cacheId == 0xFF) + return &cache->scratch; + + if (cacheId >= cache->numCaches) + return NULL; + + if (cacheEntry >= cache->numCacheEntries) + return NULL; + + return &cache->entries[cache->numCacheEntries * cacheId + cacheEntry]; +} + +/* + * DIB color palettes are arrays of RGBQUAD structs with colors in BGRX format. + * They are used only by 1, 2, 4, and 8-bit bitmaps. + */ +static void fill_gdi_palette_for_icon(ICON_INFO* iconInfo, gdiPalette* palette) +{ + UINT32 i; + palette->format = PIXEL_FORMAT_BGRX32; + ZeroMemory(palette->palette, sizeof(palette->palette)); + + if (!iconInfo->cbColorTable) + return; + + if ((iconInfo->cbColorTable % 4 != 0) || (iconInfo->cbColorTable / 4 > 256)) + { + WLog_WARN(TAG, "weird palette size: %u", iconInfo->cbColorTable); + return; + } + + for (i = 0; i < iconInfo->cbColorTable / 4; i++) + { + palette->palette[i] = ReadColor(&iconInfo->colorTable[4 * i], palette->format); + } +} + +static BOOL convert_icon_color_to_argb(ICON_INFO* iconInfo, BYTE* argbPixels) +{ + DWORD format; + gdiPalette palette; + + /* + * Color formats used by icons are DIB bitmap formats (2-bit format + * is not used by MS-RDPERP). Note that 16-bit is RGB555, not RGB565, + * and that 32-bit format uses BGRA order. + */ + switch (iconInfo->bpp) + { + case 1: + case 4: + /* + * These formats are not supported by freerdp_image_copy(). + * PIXEL_FORMAT_MONO and PIXEL_FORMAT_A4 are *not* correct + * color formats for this. Please fix freerdp_image_copy() + * if you came here to fix a broken icon of some weird app + * that still uses 1 or 4bpp format in the 21st century. + */ + WLog_WARN(TAG, "1bpp and 4bpp icons are not supported"); + return FALSE; + + case 8: + format = PIXEL_FORMAT_RGB8; + break; + + case 16: + format = PIXEL_FORMAT_RGB15; + break; + + case 24: + format = PIXEL_FORMAT_RGB24; + break; + + case 32: + format = PIXEL_FORMAT_BGRA32; + break; + + default: + WLog_WARN(TAG, "invalid icon bpp: %d", iconInfo->bpp); + return FALSE; + } + + fill_gdi_palette_for_icon(iconInfo, &palette); + return freerdp_image_copy( + argbPixels, + PIXEL_FORMAT_ARGB32, + 0, 0, 0, + iconInfo->width, + iconInfo->height, + iconInfo->bitsColor, + format, + 0, 0, 0, + &palette, + FREERDP_FLIP_VERTICAL + ); +} + +static inline UINT32 div_ceil(UINT32 a, UINT32 b) +{ + return (a + (b - 1)) / b; +} + +static inline UINT32 round_up(UINT32 a, UINT32 b) +{ + return b * div_ceil(a, b); +} + +static void apply_icon_alpha_mask(ICON_INFO* iconInfo, BYTE* argbPixels) +{ + BYTE nextBit; + BYTE* maskByte; + UINT32 x, y; + UINT32 stride; + + if (!iconInfo->cbBitsMask) + return; + + /* + * Each byte encodes 8 adjacent pixels (with LSB padding as needed). + * And due to hysterical raisins, stride of DIB bitmaps must be + * a multiple of 4 bytes. + */ + stride = round_up(div_ceil(iconInfo->width, 8), 4); + + for (y = 0; y < iconInfo->height; y++) + { + /* ɐᴉlɐɹʇsn∀ uᴉ ǝɹ,ǝʍ ʇɐɥʇ ʇǝƃɹoɟ ʇ,uop */ + maskByte = &iconInfo->bitsMask[stride * (iconInfo->height - 1 - y)]; + nextBit = 0x80; + + for (x = 0; x < iconInfo->width; x++) + { + BYTE alpha = (*maskByte & nextBit) ? 0x00 : 0xFF; + argbPixels[4 * (x + y * iconInfo->width)] &= alpha; + nextBit >>= 1; + + if (!nextBit) + { + nextBit = 0x80; + maskByte++; + } + } + } +} + +/* + * _NET_WM_ICON format is defined as "array of CARDINAL" values which for + * Xlib must be represented with an array of C's "long" values. Note that + * "long" != "INT32" on 64-bit systems. Therefore we can't simply cast + * the bitmap data as (unsigned char*), we have to copy all the pixels. + * + * The first two values are width and height followed by actual color data + * in ARGB format (e.g., 0xFFFF0000L is opaque red), pixels are in normal, + * left-to-right top-down order. + */ +static BOOL convert_rail_icon(ICON_INFO* iconInfo, xfRailIcon* railIcon) +{ + BYTE* argbPixels; + BYTE* nextPixel; + long* pixels; + int i; + int nelements; + argbPixels = calloc(iconInfo->width * iconInfo->height, 4); + + if (!argbPixels) + goto error; + + if (!convert_icon_color_to_argb(iconInfo, argbPixels)) + goto error; + + apply_icon_alpha_mask(iconInfo, argbPixels); + nelements = 2 + iconInfo->width * iconInfo->height; + pixels = realloc(railIcon->data, nelements * sizeof(long)); + + if (!pixels) + goto error; + + railIcon->data = pixels; + railIcon->length = nelements; + pixels[0] = iconInfo->width; + pixels[1] = iconInfo->height; + nextPixel = argbPixels; + + for (i = 2; i < nelements; i++) + { + pixels[i] = ReadColor(nextPixel, PIXEL_FORMAT_BGRA32); + nextPixel += 4; + } + + free(argbPixels); + return TRUE; +error: + free(argbPixels); + return FALSE; +} + +static void xf_rail_set_window_icon(xfContext* xfc, + xfAppWindow* railWindow, xfRailIcon* icon, + BOOL replace) +{ + XChangeProperty(xfc->display, railWindow->handle, xfc->_NET_WM_ICON, + XA_CARDINAL, 32, replace ? PropModeReplace : PropModeAppend, + (unsigned char*) icon->data, icon->length); + XFlush(xfc->display); +} + +static xfAppWindow* xf_rail_get_window_by_id(xfContext* xfc, UINT32 windowId) +{ + return (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, + (void*)(UINT_PTR) windowId); +} + static BOOL xf_rail_window_icon(rdpContext* context, WINDOW_ORDER_INFO* orderInfo, WINDOW_ICON_ORDER* windowIcon) { xfContext* xfc = (xfContext*) context; - xfAppWindow* railWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, - (void*)(UINT_PTR) orderInfo->windowId); + xfAppWindow* railWindow; + xfRailIcon* icon; + BOOL replaceIcon; + railWindow = xf_rail_get_window_by_id(xfc, orderInfo->windowId); if (!railWindow) - return FALSE; + return TRUE; + icon = RailIconCache_Lookup(xfc->railIconCache, + windowIcon->iconInfo->cacheId, + windowIcon->iconInfo->cacheEntry); + + if (!icon) + { + WLog_WARN(TAG, "failed to get icon from cache %02X:%04X", + windowIcon->iconInfo->cacheId, + windowIcon->iconInfo->cacheEntry); + return FALSE; + } + + if (!convert_rail_icon(windowIcon->iconInfo, icon)) + { + WLog_WARN(TAG, "failed to convert icon for window %08X", orderInfo->windowId); + return FALSE; + } + + replaceIcon = !!(orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW); + xf_rail_set_window_icon(xfc, railWindow, icon, replaceIcon); return TRUE; } static BOOL xf_rail_window_cached_icon(rdpContext* context, WINDOW_ORDER_INFO* orderInfo, WINDOW_CACHED_ICON_ORDER* windowCachedIcon) { + xfContext* xfc = (xfContext*) context; + xfAppWindow* railWindow; + xfRailIcon* icon; + BOOL replaceIcon; + railWindow = xf_rail_get_window_by_id(xfc, orderInfo->windowId); + + if (!railWindow) + return TRUE; + + icon = RailIconCache_Lookup(xfc->railIconCache, + windowCachedIcon->cachedIcon.cacheId, + windowCachedIcon->cachedIcon.cacheEntry); + + if (!icon) + { + WLog_WARN(TAG, "failed to get icon from cache %02X:%04X", + windowCachedIcon->cachedIcon.cacheId, + windowCachedIcon->cachedIcon.cacheEntry); + return FALSE; + } + + replaceIcon = !!(orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW); + xf_rail_set_window_icon(xfc, railWindow, icon, replaceIcon); return TRUE; } @@ -631,7 +962,7 @@ static void xf_rail_register_update_callbacks(rdpUpdate* update) * @return 0 on success, otherwise a Win32 error code */ static UINT xf_rail_server_execute_result(RailClientContext* context, - RAIL_EXEC_RESULT_ORDER* execResult) + const RAIL_EXEC_RESULT_ORDER* execResult) { xfContext* xfc = (xfContext*) context->custom; @@ -655,7 +986,7 @@ static UINT xf_rail_server_execute_result(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT xf_rail_server_system_param(RailClientContext* context, - RAIL_SYSPARAM_ORDER* sysparam) + const RAIL_SYSPARAM_ORDER* sysparam) { return CHANNEL_RC_OK; } @@ -666,7 +997,7 @@ static UINT xf_rail_server_system_param(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT xf_rail_server_handshake(RailClientContext* context, - RAIL_HANDSHAKE_ORDER* handshake) + const RAIL_HANDSHAKE_ORDER* handshake) { RAIL_EXEC_ORDER exec; RAIL_SYSPARAM_ORDER sysparam; @@ -722,7 +1053,7 @@ static UINT xf_rail_server_handshake(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT xf_rail_server_handshake_ex(RailClientContext* context, - RAIL_HANDSHAKE_EX_ORDER* handshakeEx) + const RAIL_HANDSHAKE_EX_ORDER* handshakeEx) { return CHANNEL_RC_OK; } @@ -733,7 +1064,7 @@ static UINT xf_rail_server_handshake_ex(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT xf_rail_server_local_move_size(RailClientContext* context, - RAIL_LOCALMOVESIZE_ORDER* localMoveSize) + const RAIL_LOCALMOVESIZE_ORDER* localMoveSize) { int x = 0, y = 0; int direction = 0; @@ -832,7 +1163,7 @@ static UINT xf_rail_server_local_move_size(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT xf_rail_server_min_max_info(RailClientContext* context, - RAIL_MINMAXINFO_ORDER* minMaxInfo) + const RAIL_MINMAXINFO_ORDER* minMaxInfo) { xfAppWindow* appWindow = NULL; xfContext* xfc = (xfContext*) context->custom; @@ -857,7 +1188,7 @@ static UINT xf_rail_server_min_max_info(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT xf_rail_server_language_bar_info(RailClientContext* context, - RAIL_LANGBAR_INFO_ORDER* langBarInfo) + const RAIL_LANGBAR_INFO_ORDER* langBarInfo) { return CHANNEL_RC_OK; } @@ -868,7 +1199,7 @@ static UINT xf_rail_server_language_bar_info(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT xf_rail_server_get_appid_response(RailClientContext* context, - RAIL_GET_APPID_RESP_ORDER* getAppIdResp) + const RAIL_GET_APPID_RESP_ORDER* getAppIdResp) { return CHANNEL_RC_OK; } @@ -907,6 +1238,14 @@ int xf_rail_init(xfContext* xfc, RailClientContext* rail) return 0; xfc->railWindows->valueFree = rail_window_free; + xfc->railIconCache = RailIconCache_New(xfc->context.settings); + + if (!xfc->railIconCache) + { + HashTable_Free(xfc->railWindows); + return 0; + } + return 1; } @@ -924,5 +1263,11 @@ int xf_rail_uninit(xfContext* xfc, RailClientContext* rail) xfc->railWindows = NULL; } + if (xfc->railIconCache) + { + RailIconCache_Free(xfc->railIconCache); + xfc->railIconCache = NULL; + } + return 1; } diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c index d28a34d..a86ad4c 100644 --- a/client/X11/xf_window.c +++ b/client/X11/xf_window.c @@ -146,15 +146,26 @@ void xf_SendClientEvent(xfContext* xfc, Window window, Atom atom, va_end(argp); } +void xf_SetWindowMinimized(xfContext* xfc, xfWindow* window) +{ + XIconifyWindow(xfc->display, window->handle, xfc->screen_number); +} + void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen) { - int i; + UINT32 i; rdpSettings* settings = xfc->context.settings; int startX, startY; UINT32 width = window->width; UINT32 height = window->height; + /* xfc->decorations is set by caller depending on settings and whether it is fullscreen or not */ window->decorations = xfc->decorations; + /* show/hide decorations (e.g. title bar) as guided by xfc->decorations */ xf_SetWindowDecorations(xfc, window->handle, window->decorations); + DEBUG_X11(TAG, "X window decoration set to %d", (int)window->decorations); + + if (xfc->floatbar) + xf_floatbar_toggle_visibility(xfc, fullscreen); if (fullscreen) { @@ -162,8 +173,8 @@ void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen) xfc->savedHeight = xfc->window->height; xfc->savedPosX = xfc->window->left; xfc->savedPosY = xfc->window->top; - startX = settings->DesktopPosX; - startY = settings->DesktopPosY; + startX = (settings->DesktopPosX != UINT32_MAX) ? settings->DesktopPosX : 0; + startY = (settings->DesktopPosY != UINT32_MAX) ? settings->DesktopPosY : 0; } else { @@ -194,7 +205,12 @@ void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen) startY += xfc->context.settings->MonitorLocalShiftY; } - if (xfc->_NET_WM_FULLSCREEN_MONITORS != None) + /* + It is safe to proceed with simply toogling _NET_WM_STATE_FULLSCREEN window state on the following conditions: + - The window manager supports multiple monitor full screen + - The user requested to use a single monitor to render the remote desktop + */ + if (xfc->_NET_WM_FULLSCREEN_MONITORS != None || settings->MonitorCount == 1) { xf_ResizeDesktopWindow(xfc, window, width, height); @@ -286,6 +302,7 @@ void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen) width = xfc->vscreen.area.right - xfc->vscreen.area.left + 1; height = xfc->vscreen.area.bottom - xfc->vscreen.area.top + 1; + DEBUG_X11("X window move and resize %dx%d@%dx%d", startX, startY, width, height); xf_ResizeDesktopWindow(xfc, window, width, height); XMoveWindow(xfc->display, window->handle, startX, startY); } @@ -541,6 +558,7 @@ xfWindow* xf_CreateDesktopWindow(xfContext* xfc, char* name, int width, XSelectInput(xfc->display, window->handle, input_mask); XClearWindow(xfc->display, window->handle); + xf_SetWindowTitleText(xfc, window->handle, name); XMapWindow(xfc->display, window->handle); xf_input_init(xfc, window->handle); @@ -563,13 +581,13 @@ xfWindow* xf_CreateDesktopWindow(xfContext* xfc, char* name, int width, { XMoveWindow(xfc->display, window->handle, 0, 0); } - else if (settings->DesktopPosX || settings->DesktopPosY) + else if (settings->DesktopPosX != UINT32_MAX && settings->DesktopPosY != UINT32_MAX) { XMoveWindow(xfc->display, window->handle, settings->DesktopPosX, settings->DesktopPosY); } - xf_SetWindowTitleText(xfc, window->handle, name); + window->floatbar = xf_floatbar_new(xfc, window->handle); return window; } @@ -591,11 +609,10 @@ void xf_ResizeDesktopWindow(xfContext* xfc, xfWindow* window, int width, size_hints->win_gravity = NorthWestGravity; size_hints->min_width = size_hints->min_height = 1; size_hints->max_width = size_hints->max_height = 16384; - XSetWMNormalHints(xfc->display, window->handle, size_hints); XResizeWindow(xfc->display, window->handle, width, height); #ifdef WITH_XRENDER - if (!settings->SmartSizing) + if (!settings->SmartSizing && !settings->DynamicResolutionUpdate) #endif { if (!xfc->fullscreen) @@ -604,10 +621,10 @@ void xf_ResizeDesktopWindow(xfContext* xfc, xfWindow* window, int width, * not be resizable */ size_hints->min_width = size_hints->max_width = width; size_hints->min_height = size_hints->max_height = height; - XSetWMNormalHints(xfc->display, window->handle, size_hints); } } + XSetWMNormalHints(xfc->display, window->handle, size_hints); XFree(size_hints); } @@ -619,6 +636,9 @@ void xf_DestroyDesktopWindow(xfContext* xfc, xfWindow* window) if (xfc->window == window) xfc->window = NULL; + if (window->floatbar) + xf_floatbar_free(xfc, window, window->floatbar); + if (window->gc) XFreeGC(xfc->display, window->gc); @@ -644,25 +664,14 @@ void xf_SetWindowStyle(xfContext* xfc, xfAppWindow* appWindow, UINT32 style, UINT32 ex_style) { Atom window_type; + BOOL redirect = FALSE; if ((ex_style & WS_EX_NOACTIVATE) || (ex_style & WS_EX_TOOLWINDOW)) { - /* - * Tooltips and menu items should be unmanaged windows - * (called "override redirect" in X windows parlance) - * If they are managed, there are issues with window focus that - * cause the windows to behave improperly. For example, a mouse - * press will dismiss a drop-down menu because the RDP server - * sees that as a focus out event from the window owning the - * dropdown. - */ - XSetWindowAttributes attrs; - attrs.override_redirect = True; - XChangeWindowAttributes(xfc->display, appWindow->handle, CWOverrideRedirect, - &attrs); + redirect = TRUE; appWindow->is_transient = TRUE; xf_SetWindowUnlisted(xfc, appWindow->handle); - window_type = xfc->_NET_WM_WINDOW_TYPE_POPUP; + window_type = xfc->_NET_WM_WINDOW_TYPE_DROPDOWN_MENU; } /* * TOPMOST window that is not a tool window is treated like a regular window (i.e. task manager). @@ -684,6 +693,22 @@ void xf_SetWindowStyle(xfContext* xfc, xfAppWindow* appWindow, UINT32 style, window_type = xfc->_NET_WM_WINDOW_TYPE_NORMAL; } + { + /* + * Tooltips and menu items should be unmanaged windows + * (called "override redirect" in X windows parlance) + * If they are managed, there are issues with window focus that + * cause the windows to behave improperly. For example, a mouse + * press will dismiss a drop-down menu because the RDP server + * sees that as a focus out event from the window owning the + * dropdown. + */ + XSetWindowAttributes attrs; + attrs.override_redirect = redirect ? True : False; + XChangeWindowAttributes(xfc->display, appWindow->handle, CWOverrideRedirect, + &attrs); + } + XChangeProperty(xfc->display, appWindow->handle, xfc->_NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (BYTE*) &window_type, 1); } @@ -971,43 +996,6 @@ void xf_ShowWindow(xfContext* xfc, xfAppWindow* appWindow, BYTE state) XFlush(xfc->display); } -#if 0 -void xf_SetWindowIcon(xfContext* xfc, xfAppWindow* appWindow, rdpIcon* icon) -{ - int x, y; - int pixels; - int propsize; - long* propdata; - long* dstp; - UINT32* srcp; - - if (!icon->big) - return; - - pixels = icon->entry->width * icon->entry->height; - propsize = 2 + pixels; - propdata = malloc(propsize * sizeof(long)); - propdata[0] = icon->entry->width; - propdata[1] = icon->entry->height; - dstp = &(propdata[2]); - srcp = (UINT32*) icon->extra; - - for (y = 0; y < icon->entry->height; y++) - { - for (x = 0; x < icon->entry->width; x++) - { - *dstp++ = *srcp++; - } - } - - XChangeProperty(xfc->display, appWindow->handle, xfc->_NET_WM_ICON, XA_CARDINAL, - 32, - PropModeReplace, (BYTE*) propdata, propsize); - XFlush(xfc->display); - free(propdata); -} -#endif - void xf_SetWindowRects(xfContext* xfc, xfAppWindow* appWindow, RECTANGLE_16* rects, int nrects) { diff --git a/client/X11/xf_window.h b/client/X11/xf_window.h index 1fdbe2d..b0ecb02 100644 --- a/client/X11/xf_window.h +++ b/client/X11/xf_window.h @@ -30,6 +30,7 @@ typedef struct xf_localmove xfLocalMove; typedef struct xf_window xfWindow; #include "xf_client.h" +#include "xf_floatbar.h" #include "xfreerdp.h" // Extended ICCM flags http://standards.freedesktop.org/wm-spec/wm-spec-latest.html @@ -80,6 +81,7 @@ struct xf_window int shmid; Window handle; Window* xfwin; + xfFloatbar* floatbar; BOOL decorations; BOOL is_mapped; BOOL is_transient; @@ -143,6 +145,7 @@ BOOL xf_GetCurrentDesktop(xfContext* xfc); BOOL xf_GetWorkArea(xfContext* xfc); void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen); +void xf_SetWindowMinimized(xfContext* xfc, xfWindow* window); void xf_SetWindowDecorations(xfContext* xfc, Window window, BOOL show); void xf_SetWindowUnlisted(xfContext* xfc, Window window); @@ -154,7 +157,7 @@ Window xf_CreateDummyWindow(xfContext* xfc); void xf_DestroyDummyWindow(xfContext* xfc, Window window); BOOL xf_GetWindowProperty(xfContext* xfc, Window window, Atom property, int length, - unsigned long* nitems, unsigned long* bytes, BYTE** prop); + unsigned long* nitems, unsigned long* bytes, BYTE** prop); void xf_SendClientEvent(xfContext* xfc, Window window, Atom atom, unsigned int numArgs, ...); int xf_AppWindowInit(xfContext* xfc, xfAppWindow* appWindow); @@ -163,13 +166,15 @@ void xf_MoveWindow(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int wid void xf_ShowWindow(xfContext* xfc, xfAppWindow* appWindow, BYTE state); //void xf_SetWindowIcon(xfContext* xfc, xfAppWindow* appWindow, rdpIcon* icon); void xf_SetWindowRects(xfContext* xfc, xfAppWindow* appWindow, RECTANGLE_16* rects, int nrects); -void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, UINT32 rectsOffsetX, UINT32 rectsOffsetY, RECTANGLE_16* rects, int nrects); +void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, UINT32 rectsOffsetX, + UINT32 rectsOffsetY, RECTANGLE_16* rects, int nrects); void xf_SetWindowStyle(xfContext* xfc, xfAppWindow* appWindow, UINT32 style, UINT32 ex_style); -void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int width, int height); +void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int width, + int height); void xf_DestroyWindow(xfContext* xfc, xfAppWindow* appWindow); void xf_SetWindowMinMaxInfo(xfContext* xfc, xfAppWindow* appWindow, - int maxWidth, int maxHeight, int maxPosX, int maxPosY, - int minTrackWidth, int minTrackHeight, int maxTrackWidth, int maxTrackHeight); + int maxWidth, int maxHeight, int maxPosX, int maxPosY, + int minTrackWidth, int minTrackHeight, int maxTrackWidth, int maxTrackHeight); void xf_StartLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow, int direction, int x, int y); void xf_EndLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow); xfAppWindow* xf_AppWindowFromX11Window(xfContext* xfc, Window wnd); diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index 04aabb0..746ea33 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -83,6 +83,7 @@ typedef struct xf_glyph xfGlyph; typedef struct xf_clipboard xfClipboard; typedef struct _xfDispContext xfDispContext; typedef struct _xfVideoContext xfVideoContext; +typedef struct xf_rail_icon_cache xfRailIconCache; /* Value of the first logical button number in X11 which must be */ /* subtracted to go from a button number in X11 to an index into */ @@ -160,6 +161,7 @@ struct xf_context BOOL use_xinput; BOOL mouse_active; BOOL fullscreen_toggle; + BOOL floatbar; BOOL controlToggle; UINT32 KeyboardLayout; BOOL KeyboardState[256]; @@ -203,6 +205,7 @@ struct xf_context Atom _NET_WM_WINDOW_TYPE_DIALOG; Atom _NET_WM_WINDOW_TYPE_UTILITY; Atom _NET_WM_WINDOW_TYPE_POPUP; + Atom _NET_WM_WINDOW_TYPE_POPUP_MENU; Atom _NET_WM_WINDOW_TYPE_DROPDOWN_MENU; Atom _NET_WM_MOVERESIZE; @@ -220,10 +223,10 @@ struct xf_context RdpeiClientContext* rdpei; EncomspClientContext* encomsp; xfDispContext* xfDisp; - DispClientContext* disp; RailClientContext* rail; wHashTable* railWindows; + xfRailIconCache* railIconCache; BOOL xkbAvailable; BOOL xrenderAvailable; @@ -278,6 +281,7 @@ enum XF_EXIT_CODE XF_EXIT_PROTOCOL = 130, XF_EXIT_CONN_FAILED = 131, XF_EXIT_AUTH_FAILURE = 132, + XF_EXIT_NEGO_FAILURE = 133, XF_EXIT_UNKNOWN = 255, }; diff --git a/client/common/client.c b/client/common/client.c index 2c8bbbb..06146a4 100644 --- a/client/common/client.c +++ b/client/common/client.c @@ -306,6 +306,7 @@ int freerdp_client_settings_parse_assistance_file(rdpSettings* settings, const char* filename) { int status; + int ret = -1; rdpAssistanceFile* file; file = freerdp_assistance_file_new(); @@ -315,15 +316,17 @@ int freerdp_client_settings_parse_assistance_file(rdpSettings* settings, status = freerdp_assistance_parse_file(file, filename); if (status < 0) - return -1; + goto out; status = freerdp_client_populate_settings_from_assistance_file(file, settings); if (status < 0) - return -1; + goto out; + ret = 0; +out: freerdp_assistance_file_free(file); - return 0; + return ret; } /** Callback set in the rdp_freerdp structure, and used to get the user's password, @@ -422,6 +425,12 @@ fail: BOOL client_cli_authenticate(freerdp* instance, char** username, char** password, char** domain) { + if (instance->settings->SmartcardLogon) + { + WLog_INFO(TAG, "Authentication via smartcard"); + return TRUE; + } + return client_cli_authenticate_raw(instance, FALSE, username, password, domain); } @@ -544,4 +553,64 @@ DWORD client_cli_verify_changed_certificate(freerdp* instance, return client_cli_accept_certificate(instance->settings); } +BOOL client_auto_reconnect(freerdp* instance) +{ + return client_auto_reconnect_ex(instance, NULL); +} + +BOOL client_auto_reconnect_ex(freerdp* instance, BOOL(*window_events)(freerdp* instance)) +{ + UINT32 maxRetries; + UINT32 numRetries = 0; + rdpSettings* settings; + + if (!instance || !instance->settings) + return FALSE; + + settings = instance->settings; + maxRetries = settings->AutoReconnectMaxRetries; + + /* Only auto reconnect on network disconnects. */ + if (freerdp_error_info(instance) != 0) + return FALSE; + + /* A network disconnect was detected */ + WLog_INFO(TAG, "Network disconnect!"); + + if (!settings->AutoReconnectionEnabled) + { + /* No auto-reconnect - just quit */ + return FALSE; + } + + /* Perform an auto-reconnect. */ + while (TRUE) + { + UINT32 x; + + /* Quit retrying if max retries has been exceeded */ + if ((maxRetries > 0) && (numRetries++ >= maxRetries)) + { + return FALSE; + } + + /* Attempt the next reconnect */ + WLog_INFO(TAG, "Attempting reconnect (%"PRIu32" of %"PRIu32")", numRetries, maxRetries); + + if (freerdp_reconnect(instance)) + return TRUE; + + for (x = 0; x < 50; x++) + { + if (!IFCALLRESULT(TRUE, window_events, instance)) + return FALSE; + + Sleep(100); + } + } + + WLog_ERR(TAG, "Maximum reconnect retries exceeded"); + return FALSE; +} + diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 801ef95..103b4d2 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -48,6 +48,16 @@ #include #define TAG CLIENT_TAG("common.cmdline") +static BOOL copy_value(const char* value, char** dst) +{ + if (!dst || !value) + return FALSE; + + free(*dst); + (*dst) = _strdup(value); + return (*dst) != NULL; +} + BOOL freerdp_client_print_version(void) { printf("This is FreeRDP version %s (%s)\n", FREERDP_VERSION_FULL, @@ -106,7 +116,7 @@ static void freerdp_client_print_command_line_args(COMMAND_LINE_ARGUMENT_A* arg) { printf(" %s", arg->Default ? "-" : "+"); printf("%-20s", arg->Name); - printf("\t%s (default:%s)\n", arg->Text, arg->Default ? "on" : "off"); + printf("\t%s %s\n", arg->Default ? "Disable" : "Enable", arg->Text); } } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); @@ -172,13 +182,13 @@ BOOL freerdp_client_print_command_line_help_ex(int argc, char** argv, } static int freerdp_client_command_line_pre_filter(void* context, int index, - int argc, LPCSTR* argv) + int argc, LPSTR* argv) { if (index == 1) { - int length; + size_t length; rdpSettings* settings; - length = (int) strlen(argv[index]); + length = strlen(argv[index]); if (length > 4) { @@ -186,7 +196,7 @@ static int freerdp_client_command_line_pre_filter(void* context, int index, { settings = (rdpSettings*) context; - if (!(settings->ConnectionFile = _strdup(argv[index]))) + if (!copy_value(argv[index], &settings->ConnectionFile)) return COMMAND_LINE_ERROR_MEMORY; return 1; @@ -199,7 +209,7 @@ static int freerdp_client_command_line_pre_filter(void* context, int index, { settings = (rdpSettings*) context; - if (!(settings->AssistanceFile = _strdup(argv[index]))) + if (!copy_value(argv[index], &settings->AssistanceFile)) return COMMAND_LINE_ERROR_MEMORY; return 1; @@ -210,6 +220,7 @@ static int freerdp_client_command_line_pre_filter(void* context, int index, return 0; } + BOOL freerdp_client_add_device_channel(rdpSettings* settings, int count, char** params) { @@ -585,11 +596,14 @@ static char** freerdp_command_line_parse_comma_separated_values_ex(const char* n { if (name) { - p = (char**) calloc(1UL, sizeof(char*)); + size_t len = strlen(name); + p = (char**) calloc(2UL + len, sizeof(char*)); if (p) { - p[0] = name; + char* dst = (char*)&p[1]; + p[0] = dst; + sprintf_s(dst, len + 1, "%s", name); *count = 1; return p; } @@ -659,6 +673,7 @@ static int freerdp_client_command_line_post_filter(void* context, { rdpSettings* settings = (rdpSettings*) context; BOOL status = TRUE; + BOOL enable = arg->Value ? TRUE : FALSE; CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "a") { @@ -745,32 +760,32 @@ static int freerdp_client_command_line_post_filter(void* context, } CommandLineSwitchCase(arg, "multitouch") { - settings->MultiTouchInput = TRUE; + settings->MultiTouchInput = enable; } CommandLineSwitchCase(arg, "gestures") { - settings->MultiTouchGestures = TRUE; + settings->MultiTouchGestures = enable; } CommandLineSwitchCase(arg, "echo") { - settings->SupportEchoChannel = TRUE; + settings->SupportEchoChannel = enable; } CommandLineSwitchCase(arg, "ssh-agent") { - settings->SupportSSHAgentChannel = TRUE; + settings->SupportSSHAgentChannel = enable; } CommandLineSwitchCase(arg, "disp") { - settings->SupportDisplayControl = TRUE; + settings->SupportDisplayControl = enable; } CommandLineSwitchCase(arg, "geometry") { - settings->SupportGeometryTracking = TRUE; + settings->SupportGeometryTracking = enable; } CommandLineSwitchCase(arg, "video") { - settings->SupportGeometryTracking = TRUE; /* this requires geometry tracking */ - settings->SupportVideoOptimized = TRUE; + settings->SupportGeometryTracking = enable; /* this requires geometry tracking */ + settings->SupportVideoOptimized = enable; } CommandLineSwitchCase(arg, "sound") { @@ -801,17 +816,21 @@ static int freerdp_client_command_line_post_filter(void* context, } CommandLineSwitchCase(arg, "heartbeat") { - settings->SupportHeartbeatPdu = TRUE; + settings->SupportHeartbeatPdu = enable; } CommandLineSwitchCase(arg, "multitransport") { - settings->SupportMultitransport = TRUE; - settings->MultitransportFlags = (TRANSPORT_TYPE_UDP_FECR | - TRANSPORT_TYPE_UDP_FECL | TRANSPORT_TYPE_UDP_PREFERRED); + settings->SupportMultitransport = enable; + + if (settings->SupportMultitransport) + settings->MultitransportFlags = (TRANSPORT_TYPE_UDP_FECR | + TRANSPORT_TYPE_UDP_FECL | TRANSPORT_TYPE_UDP_PREFERRED); + else + settings->MultitransportFlags = 0; } CommandLineSwitchCase(arg, "password-is-pin") { - settings->PasswordIsSmartcardPin = TRUE; + settings->PasswordIsSmartcardPin = enable; } CommandLineSwitchEnd(arg) return status ? 1 : -1; @@ -976,6 +995,10 @@ BOOL freerdp_set_connection_type(rdpSettings* settings, int type) settings->DisableThemes = FALSE; settings->NetworkAutoDetect = TRUE; } + else + { + return FALSE; + } return TRUE; } @@ -996,7 +1019,7 @@ int freerdp_map_keyboard_layout_name_to_id(char* name) id = layouts[i].code; } - free(layouts); + freerdp_keyboard_layouts_free(layouts); if (id) return id; @@ -1012,7 +1035,7 @@ int freerdp_map_keyboard_layout_name_to_id(char* name) id = layouts[i].code; } - free(layouts); + freerdp_keyboard_layouts_free(layouts); if (id) return id; @@ -1028,7 +1051,7 @@ int freerdp_map_keyboard_layout_name_to_id(char* name) id = layouts[i].code; } - free(layouts); + freerdp_keyboard_layouts_free(layouts); if (id) return id; @@ -1037,7 +1060,7 @@ int freerdp_map_keyboard_layout_name_to_id(char* name) } static int freerdp_detect_command_line_pre_filter(void* context, int index, - int argc, LPCSTR* argv) + int argc, LPSTR* argv) { int length; @@ -1083,7 +1106,7 @@ static int freerdp_detect_windows_style_command_line_syntax(int argc, char** arg *count = 0; detect_status = 0; CommandLineClearArgumentsA(args); - status = CommandLineParseArgumentsA(argc, (const char**) argv, args, flags, + status = CommandLineParseArgumentsA(argc, argv, args, flags, NULL, freerdp_detect_command_line_pre_filter, NULL); if (status < 0) @@ -1125,7 +1148,7 @@ int freerdp_detect_posix_style_command_line_syntax(int argc, char** argv, *count = 0; detect_status = 0; CommandLineClearArgumentsA(args); - status = CommandLineParseArgumentsA(argc, (const char**) argv, args, flags, + status = CommandLineParseArgumentsA(argc, argv, args, flags, NULL, freerdp_detect_command_line_pre_filter, NULL); if (status < 0) @@ -1237,7 +1260,7 @@ int freerdp_client_settings_command_line_status_print_ex(rdpSettings* settings, for (i = 0; layouts[i].code; i++) printf("0x%08"PRIX32"\t%s\n", layouts[i].code, layouts[i].name); - free(layouts); + freerdp_keyboard_layouts_free(layouts); layouts = freerdp_keyboard_get_layouts(RDP_KEYBOARD_LAYOUT_TYPE_VARIANT); //if (!layouts) /* FIXME*/ printf("\nKeyboard Layout Variants\n"); @@ -1245,7 +1268,7 @@ int freerdp_client_settings_command_line_status_print_ex(rdpSettings* settings, for (i = 0; layouts[i].code; i++) printf("0x%08"PRIX32"\t%s\n", layouts[i].code, layouts[i].name); - free(layouts); + freerdp_keyboard_layouts_free(layouts); layouts = freerdp_keyboard_get_layouts(RDP_KEYBOARD_LAYOUT_TYPE_IME); //if (!layouts) /* FIXME*/ printf("\nKeyboard Input Method Editors (IMEs)\n"); @@ -1253,7 +1276,7 @@ int freerdp_client_settings_command_line_status_print_ex(rdpSettings* settings, for (i = 0; layouts[i].code; i++) printf("0x%08"PRIX32"\t%s\n", layouts[i].code, layouts[i].name); - free(layouts); + freerdp_keyboard_layouts_free(layouts); printf("\n"); } @@ -1285,6 +1308,53 @@ static BOOL ends_with(const char* str, const char* ext) return strncmp(&str[strLen - extLen], ext, extLen) == 0; } + +static void activate_smartcard_logon_rdp(rdpSettings* settings) +{ + settings->SmartcardLogon = TRUE; + /* TODO: why not? settings->UseRdpSecurityLayer = TRUE; */ + freerdp_set_param_bool(settings, FreeRDP_PasswordIsSmartcardPin, TRUE); +} + +/** + * parses a string value with the format x + * @param input: input string + * @param v1: pointer to output v1 + * @param v2: pointer to output v2 + * @return if the parsing was successful + */ +static BOOL parseSizeValue(const char *input, unsigned long *v1, unsigned long *v2) +{ + const char *xcharpos; + char *endPtr; + unsigned long v; + + errno = 0; + v = strtoul(input, &endPtr, 10); + + if ((v == 0 || v == ULONG_MAX) && (errno != 0)) + return FALSE; + if (v1) + *v1 = v; + + xcharpos = strchr(input, 'x'); + if (!xcharpos || xcharpos != endPtr) + return FALSE; + + errno = 0; + v = strtoul(xcharpos + 1, &endPtr, 10); + + if ((v == 0 || v == ULONG_MAX) && (errno != 0)) + return FALSE; + + if (*endPtr != '\0') + return FALSE; + if (v2) + *v2 = v; + + return TRUE; +} + int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, int argc, char** argv, BOOL allowUnknown) { @@ -1315,7 +1385,11 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, allowUnknown); else compatibility = freerdp_client_detect_command_line(argc - 1, &argv[1], &flags, - allowUnknown); + allowUnknown); + + settings->ProxyHostname = NULL; + settings->ProxyUsername = NULL; + settings->ProxyPassword = NULL; if (compatibility) { @@ -1341,7 +1415,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineClearArgumentsA(args); - status = CommandLineParseArgumentsA(argc, (const char**) argv, args, flags, + status = CommandLineParseArgumentsA(argc, argv, args, flags, settings, freerdp_client_command_line_pre_filter, freerdp_client_command_line_post_filter); @@ -1356,6 +1430,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, do { + BOOL enable = arg->Value ? TRUE : FALSE; + if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)) continue; @@ -1423,14 +1499,48 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "spn-class") { - free(settings->AuthenticationServiceClass); - - if (!(settings->AuthenticationServiceClass = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->AuthenticationServiceClass)) return COMMAND_LINE_ERROR_MEMORY; } + CommandLineSwitchCase(arg, "redirect-prefer") + { + size_t count = 0; + char* cur = arg->Value; + settings->RedirectionPreferType = 0; + + do + { + UINT32 mask; + char* next = strchr(cur, ','); + + if (next) + { + *next = '\0'; + next++; + } + + if (_strnicmp(cur, "fqdn", 5) == 0) + mask = 0x06U; + else if (_strnicmp(cur, "ip", 3) == 0) + mask = 0x05U; + else if (_strnicmp(cur, "netbios", 8) == 0) + mask = 0x03U; + else + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + + cur = next; + mask = (mask & 0x07); + settings->RedirectionPreferType |= mask << (count * 3); + count++; + } + while (cur != NULL); + + if (count > 3) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + } CommandLineSwitchCase(arg, "credentials-delegation") { - settings->DisableCredentialsDelegation = arg->Value ? FALSE : TRUE; + settings->DisableCredentialsDelegation = !enable; } CommandLineSwitchCase(arg, "vmconnect") { @@ -1441,9 +1551,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (arg->Flags & COMMAND_LINE_VALUE_PRESENT) { settings->SendPreconnectionPdu = TRUE; - free(settings->PreconnectionBlob); - if (!(settings->PreconnectionBlob = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->PreconnectionBlob)) return COMMAND_LINE_ERROR_MEMORY; } } @@ -1467,39 +1576,23 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "size") { - if (!(str = _strdup(arg->Value))) - return COMMAND_LINE_ERROR_MEMORY; - p = strchr(str, 'x'); + p = strchr(arg->Value, 'x'); if (p) { - *p = '\0'; - { - long val = strtol(str, NULL, 0); + unsigned long w, h; + if (!parseSizeValue(arg->Value, &w, &h) || (w > UINT16_MAX) || (h > UINT16_MAX)) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - if ((errno != 0) || (val <= 0) || (val > UINT16_MAX)) - { - free(str); - return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - } - - settings->DesktopWidth = val; - } - { - long val = strtol(&p[1], NULL, 0); - - if ((errno != 0) || (val <= 0) || (val > UINT16_MAX)) - { - free(str); - return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - } - - settings->DesktopHeight = val; - } + settings->DesktopWidth = w; + settings->DesktopHeight = h; } else { + if (!(str = _strdup(arg->Value))) + return COMMAND_LINE_ERROR_MEMORY; + p = strchr(str, '%'); if (p) @@ -1537,13 +1630,13 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, settings->PercentScreen = val; } } - } - free(str); + free(str); + } } CommandLineSwitchCase(arg, "f") { - settings->Fullscreen = TRUE; + settings->Fullscreen = enable; } CommandLineSwitchCase(arg, "multimon") { @@ -1559,11 +1652,11 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "span") { - settings->SpanMonitors = TRUE; + settings->SpanMonitors = enable; } CommandLineSwitchCase(arg, "workarea") { - settings->Workarea = TRUE; + settings->Workarea = enable; } CommandLineSwitchCase(arg, "monitors") { @@ -1597,18 +1690,16 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "monitor-list") { - settings->ListMonitors = TRUE; + settings->ListMonitors = enable; } CommandLineSwitchCase(arg, "t") { - free(settings->WindowTitle); - - if (!(settings->WindowTitle = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->WindowTitle)) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "decorations") { - settings->Decorations = arg->Value ? TRUE : FALSE; + settings->Decorations = enable; } CommandLineSwitchCase(arg, "dynamic-resolution") { @@ -1633,34 +1724,13 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (arg->Value) { - if (!(str = _strdup(arg->Value))) - return COMMAND_LINE_ERROR_MEMORY; + unsigned long w, h; - if ((p = strchr(str, 'x'))) - { - unsigned long w, h; - *p = '\0'; - w = strtoul(str, NULL, 0); + if (!parseSizeValue(arg->Value, &w, &h) || (w > UINT16_MAX) || (h > UINT16_MAX)) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - if ((errno != 0) || (w == 0) || (w > UINT16_MAX)) - { - free(str); - return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - } - - h = strtoul(&p[1], NULL, 0); - - if ((errno != 0) || (h == 0) || (h > UINT16_MAX)) - { - free(str); - return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - } - - settings->SmartSizingWidth = w; - settings->SmartSizingHeight = h; - } - - free(str); + settings->SmartSizingWidth = w; + settings->SmartSizingHeight = h; } } CommandLineSwitchCase(arg, "bpp") @@ -1687,27 +1757,28 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "admin") { - settings->ConsoleSession = TRUE; + settings->ConsoleSession = enable; + } + CommandLineSwitchCase(arg, "relax-order-checks") + { + settings->AllowUnanouncedOrdersFromServer = enable; } CommandLineSwitchCase(arg, "restricted-admin") { - settings->ConsoleSession = TRUE; - settings->RestrictedAdminModeRequired = TRUE; + settings->ConsoleSession = enable; + settings->RestrictedAdminModeRequired = enable; } CommandLineSwitchCase(arg, "pth") { settings->ConsoleSession = TRUE; settings->RestrictedAdminModeRequired = TRUE; - free(settings->PasswordHash); - if (!(settings->PasswordHash = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->PasswordHash)) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "client-hostname") { - free(settings->ClientHostname); - - if (!(settings->ClientHostname = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->ClientHostname)) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "kbd") @@ -1765,16 +1836,12 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "d") { - free(settings->Domain); - - if (!(settings->Domain = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->Domain)) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "p") { - free(settings->Password); - - if (!(settings->Password = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->Password)) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "g") @@ -1819,27 +1886,76 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "proxy") { + /* initial value */ + settings->ProxyType = PROXY_TYPE_HTTP; + if (arg->Flags & COMMAND_LINE_VALUE_PRESENT) { + char* atPtr; + /* value is [scheme://][user:password@]hostname:port */ p = strstr(arg->Value, "://"); if (p) { *p = '\0'; - if (!strcmp("http", arg->Value)) - { + if (_stricmp("no_proxy", arg->Value) == 0) + settings->ProxyType = PROXY_TYPE_IGNORE; + + if (_stricmp("http", arg->Value) == 0) settings->ProxyType = PROXY_TYPE_HTTP; - } + else if (_stricmp("socks5", arg->Value) == 0) + settings->ProxyType = PROXY_TYPE_SOCKS; else { - WLog_ERR(TAG, "Only HTTP proxys supported by now"); + WLog_ERR(TAG, "Only HTTP and SOCKS5 proxies supported by now"); return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; } arg->Value = p + 3; } + /* arg->Value is now [user:password@]hostname:port */ + atPtr = strrchr(arg->Value, '@'); + + if (atPtr) + { + /* got a login / password, + * atPtr + * v + * [user:password@]hostname:port + * ^ + * colonPtr + */ + char* colonPtr = strchr(arg->Value, ':'); + + if (!colonPtr || (colonPtr > atPtr)) + { + WLog_ERR(TAG, "invalid syntax for proxy, expected syntax is user:password@host:port"); + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + } + + *colonPtr = '\0'; + settings->ProxyUsername = _strdup(arg->Value); + + if (!settings->ProxyUsername) + { + WLog_ERR(TAG, "unable to allocate proxy username"); + return COMMAND_LINE_ERROR_MEMORY; + } + + *atPtr = '\0'; + settings->ProxyPassword = _strdup(colonPtr + 1); + + if (!settings->ProxyPassword) + { + WLog_ERR(TAG, "unable to allocate proxy password"); + return COMMAND_LINE_ERROR_MEMORY; + } + + arg->Value = atPtr + 1; + } + p = strchr(arg->Value, ':'); if (p) @@ -1854,7 +1970,6 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, settings->ProxyHostname = (char*) malloc(length + 1); strncpy(settings->ProxyHostname, arg->Value, length); settings->ProxyHostname[length] = '\0'; - settings->ProxyType = PROXY_TYPE_HTTP; } } else @@ -1872,18 +1987,14 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "gd") { - free(settings->GatewayDomain); - - if (!(settings->GatewayDomain = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->GatewayDomain)) return COMMAND_LINE_ERROR_MEMORY; settings->GatewayUseSameCredentials = FALSE; } CommandLineSwitchCase(arg, "gp") { - free(settings->GatewayPassword); - - if (!(settings->GatewayPassword = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->GatewayPassword)) return COMMAND_LINE_ERROR_MEMORY; settings->GatewayUseSameCredentials = FALSE; @@ -1908,39 +2019,35 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "gat") { - free(settings->GatewayAccessToken); - - if (!(settings->GatewayAccessToken = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->GatewayAccessToken)) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "gateway-usage-method") { - long type; + long type = 0; char* pEnd; - type = strtol(arg->Value, &pEnd, 10); - if (errno != 0) - return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - - if (type == 0) + if (_stricmp(arg->Value, "none") == 0) + type = TSC_PROXY_MODE_NONE_DIRECT; + else if (_stricmp(arg->Value, "direct") == 0) + type = TSC_PROXY_MODE_DIRECT; + else if (_stricmp(arg->Value, "detect") == 0) + type = TSC_PROXY_MODE_DETECT; + else if (_stricmp(arg->Value, "default") == 0) + type = TSC_PROXY_MODE_DEFAULT; + else { - if (_stricmp(arg->Value, "none") == 0) - type = TSC_PROXY_MODE_NONE_DIRECT; - else if (_stricmp(arg->Value, "direct") == 0) - type = TSC_PROXY_MODE_DIRECT; - else if (_stricmp(arg->Value, "detect") == 0) - type = TSC_PROXY_MODE_DETECT; - else if (_stricmp(arg->Value, "default") == 0) - type = TSC_PROXY_MODE_DEFAULT; + type = strtol(arg->Value, &pEnd, 10); + + if (errno != 0) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; } freerdp_set_gateway_usage_method(settings, (UINT32) type); } CommandLineSwitchCase(arg, "app") { - free(settings->RemoteApplicationProgram); - - if (!(settings->RemoteApplicationProgram = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->RemoteApplicationProgram)) return COMMAND_LINE_ERROR_MEMORY; settings->RemoteApplicationMode = TRUE; @@ -1951,9 +2058,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "load-balance-info") { - free(settings->LoadBalanceInfo); - - if (!(settings->LoadBalanceInfo = (BYTE*) _strdup(arg->Value))) + if (!copy_value(arg->Value, (char**)&settings->LoadBalanceInfo)) return COMMAND_LINE_ERROR_MEMORY; settings->LoadBalanceInfoLength = (UINT32) strlen((char*) @@ -1961,46 +2066,36 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "app-name") { - free(settings->RemoteApplicationName); - - if (!(settings->RemoteApplicationName = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->RemoteApplicationName)) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "app-icon") { - free(settings->RemoteApplicationIcon); - - if (!(settings->RemoteApplicationIcon = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->RemoteApplicationIcon)) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "app-cmd") { - free(settings->RemoteApplicationCmdLine); - - if (!(settings->RemoteApplicationCmdLine = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->RemoteApplicationCmdLine)) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "app-file") { - free(settings->RemoteApplicationFile); - - if (!(settings->RemoteApplicationFile = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->RemoteApplicationFile)) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "app-guid") { - free(settings->RemoteApplicationGuid); - - if (!(settings->RemoteApplicationGuid = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->RemoteApplicationGuid)) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "compression") { - settings->CompressionEnabled = arg->Value ? TRUE : FALSE; + settings->CompressionEnabled = enable; } CommandLineSwitchCase(arg, "compression-level") { - unsigned long val = strtol(arg->Value, NULL, 0); + unsigned long val = strtoul(arg->Value, NULL, 0); if ((errno != 0) || (val > UINT32_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; @@ -2009,32 +2104,28 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "drives") { - settings->RedirectDrives = arg->Value ? TRUE : FALSE; + settings->RedirectDrives = enable; } CommandLineSwitchCase(arg, "home-drive") { - settings->RedirectHomeDrive = arg->Value ? TRUE : FALSE; + settings->RedirectHomeDrive = enable; } CommandLineSwitchCase(arg, "ipv6") { - settings->PreferIPv6OverIPv4 = TRUE; + settings->PreferIPv6OverIPv4 = enable; } CommandLineSwitchCase(arg, "clipboard") { - settings->RedirectClipboard = arg->Value ? TRUE : FALSE; + settings->RedirectClipboard = enable; } CommandLineSwitchCase(arg, "shell") { - free(settings->AlternateShell); - - if (!(settings->AlternateShell = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->AlternateShell)) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "shell-dir") { - free(settings->ShellWorkingDirectory); - - if (!(settings->ShellWorkingDirectory = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->ShellWorkingDirectory)) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "audio-mode") @@ -2060,33 +2151,33 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "network") { - long type; + long type = 0; char* pEnd; - type = strtol(arg->Value, &pEnd, 10); - if (errno != 0) - return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - - if (type == 0) + if (_stricmp(arg->Value, "modem") == 0) + type = CONNECTION_TYPE_MODEM; + else if (_stricmp(arg->Value, "broadband") == 0) + type = CONNECTION_TYPE_BROADBAND_HIGH; + else if (_stricmp(arg->Value, "broadband-low") == 0) + type = CONNECTION_TYPE_BROADBAND_LOW; + else if (_stricmp(arg->Value, "broadband-high") == 0) + type = CONNECTION_TYPE_BROADBAND_HIGH; + else if (_stricmp(arg->Value, "wan") == 0) + type = CONNECTION_TYPE_WAN; + else if (_stricmp(arg->Value, "lan") == 0) + type = CONNECTION_TYPE_LAN; + else if ((_stricmp(arg->Value, "autodetect") == 0) || + (_stricmp(arg->Value, "auto") == 0) || + (_stricmp(arg->Value, "detect") == 0)) { - if (_stricmp(arg->Value, "modem") == 0) - type = CONNECTION_TYPE_MODEM; - else if (_stricmp(arg->Value, "broadband") == 0) - type = CONNECTION_TYPE_BROADBAND_HIGH; - else if (_stricmp(arg->Value, "broadband-low") == 0) - type = CONNECTION_TYPE_BROADBAND_LOW; - else if (_stricmp(arg->Value, "broadband-high") == 0) - type = CONNECTION_TYPE_BROADBAND_HIGH; - else if (_stricmp(arg->Value, "wan") == 0) - type = CONNECTION_TYPE_WAN; - else if (_stricmp(arg->Value, "lan") == 0) - type = CONNECTION_TYPE_LAN; - else if ((_stricmp(arg->Value, "autodetect") == 0) || - (_stricmp(arg->Value, "auto") == 0) || - (_stricmp(arg->Value, "detect") == 0)) - { - type = CONNECTION_TYPE_AUTODETECT; - } + type = CONNECTION_TYPE_AUTODETECT; + } + else + { + type = strtol(arg->Value, &pEnd, 10); + + if (errno != 0) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; } if (!freerdp_set_connection_type(settings, type)) @@ -2094,27 +2185,43 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "fonts") { - settings->AllowFontSmoothing = arg->Value ? TRUE : FALSE; + settings->AllowFontSmoothing = enable; } CommandLineSwitchCase(arg, "wallpaper") { - settings->DisableWallpaper = arg->Value ? FALSE : TRUE; + settings->DisableWallpaper = !enable; } CommandLineSwitchCase(arg, "window-drag") { - settings->DisableFullWindowDrag = arg->Value ? FALSE : TRUE; + settings->DisableFullWindowDrag = !enable; + } + CommandLineSwitchCase(arg, "window-position") + { + unsigned long x, y; + + if (!arg->Value) + return COMMAND_LINE_ERROR_MISSING_ARGUMENT; + + if (!parseSizeValue(arg->Value, &x, &y) || x > UINT16_MAX || y > UINT16_MAX) + { + WLog_ERR(TAG, "invalid window-position argument"); + return COMMAND_LINE_ERROR_MISSING_ARGUMENT; + } + + settings->DesktopPosX = x; + settings->DesktopPosY = y; } CommandLineSwitchCase(arg, "menu-anims") { - settings->DisableMenuAnims = arg->Value ? FALSE : TRUE; + settings->DisableMenuAnims = !enable; } CommandLineSwitchCase(arg, "themes") { - settings->DisableThemes = arg->Value ? FALSE : TRUE; + settings->DisableThemes = !enable; } CommandLineSwitchCase(arg, "aero") { - settings->AllowDesktopComposition = arg->Value ? TRUE : FALSE; + settings->AllowDesktopComposition = enable; } CommandLineSwitchCase(arg, "gdi") { @@ -2131,24 +2238,24 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, { #ifdef WITH_GFX_H264 - if (_strnicmp("AVC444", arg->Value, 6) == 0) + if (_strnicmp("AVC444", arg->Value, 7) == 0) { settings->GfxH264 = TRUE; settings->GfxAVC444 = TRUE; } - else if (_strnicmp("AVC420", arg->Value, 6) == 0) + else if (_strnicmp("AVC420", arg->Value, 7) == 0) { settings->GfxH264 = TRUE; } else #endif - if (_strnicmp("RFX", arg->Value, 3) != 0) + if (_strnicmp("RFX", arg->Value, 4) != 0) return COMMAND_LINE_ERROR; } } CommandLineSwitchCase(arg, "gfx-thin-client") { - settings->GfxThinClient = arg->Value ? TRUE : FALSE; + settings->GfxThinClient = enable; if (settings->GfxThinClient) settings->GfxSmallCache = TRUE; @@ -2157,14 +2264,18 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "gfx-small-cache") { - settings->GfxSmallCache = arg->Value ? TRUE : FALSE; - settings->SupportGraphicsPipeline = TRUE; + settings->GfxSmallCache = enable; + + if (enable) + settings->SupportGraphicsPipeline = TRUE; } CommandLineSwitchCase(arg, "gfx-progressive") { - settings->GfxProgressive = arg->Value ? TRUE : FALSE; - settings->GfxThinClient = settings->GfxProgressive ? FALSE : TRUE; - settings->SupportGraphicsPipeline = TRUE; + settings->GfxProgressive = enable; + settings->GfxThinClient = !enable; + + if (enable) + settings->SupportGraphicsPipeline = TRUE; } #ifdef WITH_GFX_H264 CommandLineSwitchCase(arg, "gfx-h264") @@ -2174,18 +2285,18 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (arg->Value) { - if (_strnicmp("AVC444", arg->Value, 6) == 0) + if (_strnicmp("AVC444", arg->Value, 7) == 0) { settings->GfxAVC444 = TRUE; } - else if (_strnicmp("AVC420", arg->Value, 6) != 0) + else if (_strnicmp("AVC420", arg->Value, 7) != 0) return COMMAND_LINE_ERROR; } } #endif CommandLineSwitchCase(arg, "rfx") { - settings->RemoteFxCodec = TRUE; + settings->RemoteFxCodec = enable; } CommandLineSwitchCase(arg, "rfx-mode") { @@ -2205,12 +2316,12 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "nsc") { - settings->NSCodec = TRUE; + settings->NSCodec = enable; } #if defined(WITH_JPEG) CommandLineSwitchCase(arg, "jpeg") { - settings->JpegCodec = TRUE; + settings->JpegCodec = enable; settings->JpegQuality = 75; } CommandLineSwitchCase(arg, "jpeg-quality") @@ -2225,14 +2336,13 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, #endif CommandLineSwitchCase(arg, "nego") { - settings->NegotiateSecurityLayer = arg->Value ? TRUE : FALSE; + settings->NegotiateSecurityLayer = enable; } CommandLineSwitchCase(arg, "pcb") { settings->SendPreconnectionPdu = TRUE; - free(settings->PreconnectionBlob); - if (!(settings->PreconnectionBlob = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->PreconnectionBlob)) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "pcid") @@ -2333,19 +2443,19 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "sec-rdp") { - settings->RdpSecurity = arg->Value ? TRUE : FALSE; + settings->RdpSecurity = enable; } CommandLineSwitchCase(arg, "sec-tls") { - settings->TlsSecurity = arg->Value ? TRUE : FALSE; + settings->TlsSecurity = enable; } CommandLineSwitchCase(arg, "sec-nla") { - settings->NlaSecurity = arg->Value ? TRUE : FALSE; + settings->NlaSecurity = enable; } CommandLineSwitchCase(arg, "sec-ext") { - settings->ExtSecurity = arg->Value ? TRUE : FALSE; + settings->ExtSecurity = enable; } CommandLineSwitchCase(arg, "tls-ciphers") { @@ -2367,44 +2477,55 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, return COMMAND_LINE_ERROR_MEMORY; } } + CommandLineSwitchCase(arg, "tls-seclevel") + { + unsigned long val = strtoul(arg->Value, NULL, 0); + + if ((errno != 0) || (val > 5)) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + + settings->TlsSecLevel = val; + } CommandLineSwitchCase(arg, "cert-name") { - free(settings->CertificateName); - - if (!(settings->CertificateName = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->CertificateName)) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "cert-ignore") { - settings->IgnoreCertificate = TRUE; + settings->IgnoreCertificate = enable; } CommandLineSwitchCase(arg, "cert-tofu") { - settings->AutoAcceptCertificate = TRUE; + settings->AutoAcceptCertificate = enable; } CommandLineSwitchCase(arg, "authentication") { - settings->Authentication = arg->Value ? TRUE : FALSE; + settings->Authentication = enable; } CommandLineSwitchCase(arg, "encryption") { - settings->UseRdpSecurityLayer = arg->Value ? FALSE : TRUE; + settings->UseRdpSecurityLayer = !enable; } CommandLineSwitchCase(arg, "grab-keyboard") { - settings->GrabKeyboard = arg->Value ? TRUE : FALSE; + settings->GrabKeyboard = enable; } CommandLineSwitchCase(arg, "unmap-buttons") { - settings->UnmapButtons = arg->Value ? TRUE : FALSE; + settings->UnmapButtons = enable; } CommandLineSwitchCase(arg, "toggle-fullscreen") { - settings->ToggleFullscreen = arg->Value ? TRUE : FALSE; + settings->ToggleFullscreen = enable; + } + CommandLineSwitchCase(arg, "floatbar") + { + settings->Floatbar = enable; } CommandLineSwitchCase(arg, "mouse-motion") { - settings->MouseMotion = arg->Value ? TRUE : FALSE; + settings->MouseMotion = enable; } CommandLineSwitchCase(arg, "parent-window") { @@ -2417,11 +2538,11 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "bitmap-cache") { - settings->BitmapCacheEnabled = arg->Value ? TRUE : FALSE; + settings->BitmapCacheEnabled = enable; } CommandLineSwitchCase(arg, "offscreen-cache") { - settings->OffscreenSupportLevel = arg->Value ? TRUE : FALSE; + settings->OffscreenSupportLevel = enable; } CommandLineSwitchCase(arg, "glyph-cache") { @@ -2454,8 +2575,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "fast-path") { - settings->FastPathInput = arg->Value ? TRUE : FALSE; - settings->FastPathOutput = arg->Value ? TRUE : FALSE; + settings->FastPathInput = enable; + settings->FastPathOutput = enable; } CommandLineSwitchCase(arg, "max-fast-path-size") { @@ -2488,43 +2609,35 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "async-input") { - settings->AsyncInput = arg->Value ? TRUE : FALSE; + settings->AsyncInput = enable; } CommandLineSwitchCase(arg, "async-update") { - settings->AsyncUpdate = arg->Value ? TRUE : FALSE; + settings->AsyncUpdate = enable; } CommandLineSwitchCase(arg, "async-channels") { - settings->AsyncChannels = arg->Value ? TRUE : FALSE; - } - CommandLineSwitchCase(arg, "async-transport") - { - settings->AsyncTransport = arg->Value ? TRUE : FALSE; + settings->AsyncChannels = enable; } CommandLineSwitchCase(arg, "wm-class") { - free(settings->WmClass); - - if (!(settings->WmClass = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->WmClass)) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "play-rfx") { - free(settings->PlayRemoteFxFile); - - if (!(settings->PlayRemoteFxFile = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->PlayRemoteFxFile)) return COMMAND_LINE_ERROR_MEMORY; settings->PlayRemoteFx = TRUE; } CommandLineSwitchCase(arg, "auth-only") { - settings->AuthenticationOnly = arg->Value ? TRUE : FALSE; + settings->AuthenticationOnly = enable; } CommandLineSwitchCase(arg, "auto-reconnect") { - settings->AutoReconnectionEnabled = arg->Value ? TRUE : FALSE; + settings->AutoReconnectionEnabled = enable; } CommandLineSwitchCase(arg, "auto-reconnect-max-retries") { @@ -2540,7 +2653,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "reconnect-cookie") { - BYTE* base64; + BYTE* base64 = NULL; int length; crypto_base64_decode((const char*)(arg->Value), (int) strlen(arg->Value), &base64, &length); @@ -2548,23 +2661,23 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if ((base64 != NULL) && (length == sizeof(ARC_SC_PRIVATE_PACKET))) { memcpy(settings->ServerAutoReconnectCookie, base64, length); - free(base64); } else { WLog_ERR(TAG, "reconnect-cookie: invalid base64 '%s'", arg->Value); } + + free(base64); } CommandLineSwitchCase(arg, "print-reconnect-cookie") { - settings->PrintReconnectCookie = arg->Value ? TRUE : FALSE; + settings->PrintReconnectCookie = enable; } CommandLineSwitchCase(arg, "assistance") { settings->RemoteAssistanceMode = TRUE; - free(settings->RemoteAssistancePassword); - if (!(settings->RemoteAssistancePassword = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->RemoteAssistancePassword)) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "pwidth") @@ -2594,6 +2707,10 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, settings->DesktopOrientation = val; } + CommandLineSwitchCase(arg, "old-license") + { + settings->OldLicenseBehaviour = TRUE; + } CommandLineSwitchCase(arg, "scale") { unsigned long scaleFactor = strtoul(arg->Value, NULL, 0); @@ -2649,14 +2766,17 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "action-script") { - free(settings->ActionScript); - - if (!(settings->ActionScript = _strdup(arg->Value))) + if (!copy_value(arg->Value, &settings->ActionScript)) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "fipsmode") { - settings->FIPSMode = TRUE; + settings->FIPSMode = enable; + } + CommandLineSwitchCase(arg, "smartcard-logon") + { + if (!settings->SmartcardLogon) + activate_smartcard_logon_rdp(settings); } CommandLineSwitchDefault(arg) { diff --git a/client/common/cmdline.h b/client/common/cmdline.h index 8785ed6..7f1d9e0 100644 --- a/client/common/cmdline.h +++ b/client/common/cmdline.h @@ -27,7 +27,7 @@ static COMMAND_LINE_ARGUMENT_A args[] = { "a", COMMAND_LINE_VALUE_REQUIRED, "[,]", NULL, NULL, -1, "addin", "Addin" }, { "action-script", COMMAND_LINE_VALUE_REQUIRED, "", "~/.config/freerdp/action.sh", NULL, -1, NULL, "Action script" }, { "admin", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, "console", "Admin (or console) session" }, - { "aero", COMMAND_LINE_VALUE_BOOL, NULL, NULL, BoolValueFalse, -1, NULL, "Enable desktop composition" }, + { "aero", COMMAND_LINE_VALUE_BOOL, NULL, NULL, BoolValueFalse, -1, NULL, "desktop composition" }, { "app", COMMAND_LINE_VALUE_REQUIRED, " or ||", NULL, NULL, -1, NULL, "Remote application program" }, { "app-cmd", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Remote application command-line parameters" }, { "app-file", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "File to open with remote application" }, @@ -37,14 +37,13 @@ static COMMAND_LINE_ARGUMENT_A args[] = { "assistance", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Remote assistance password" }, { "async-channels", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Asynchronous channels (experimental)" }, { "async-input", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Asynchronous input" }, - { "async-transport", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Asynchronous transport (experimental)" }, { "async-update", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Asynchronous update" }, { "audio-mode", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Audio output mode" }, { "auth-only", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Authenticate only" }, { "authentication", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Authentication (expermiental)" }, { "auto-reconnect", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Automatic reconnection" }, { "auto-reconnect-max-retries", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Automatic reconnection maximum retries, 0 for unlimited [0,1000]" }, - { "bitmap-cache", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Enable bitmap cache" }, + { "bitmap-cache", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "bitmap cache" }, { "bpp", COMMAND_LINE_VALUE_REQUIRED, "", "16", NULL, -1, NULL, "Session bpp (color depth)" }, { "buildconfig", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_BUILDCONFIG, NULL, NULL, NULL, -1, NULL, "Print the build configuration" }, { "cert-ignore", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Ignore certificate" }, @@ -53,9 +52,9 @@ static COMMAND_LINE_ARGUMENT_A args[] = { "client-hostname", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Client Hostname to send to server" }, { "clipboard", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Redirect clipboard" }, { "codec-cache", COMMAND_LINE_VALUE_REQUIRED, "rfx|nsc|jpeg", NULL, NULL, -1, NULL, "Bitmap codec cache" }, - { "compression", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, "z", "Enable compression" }, + { "compression", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, "z", "compression" }, { "compression-level", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Compression level (0,1,2)" }, - { "credentials-delegation", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Disable credentials delegation" }, + { "credentials-delegation", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "credentials delegation" }, { "d", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Domain" }, { "decorations", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Window decorations" }, { "disp", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Display control" }, @@ -67,9 +66,10 @@ static COMMAND_LINE_ARGUMENT_A args[] = { "encryption", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Encryption (experimental)" }, { "encryption-methods", COMMAND_LINE_VALUE_REQUIRED, "[40,][56,][128,][FIPS]", NULL, NULL, -1, NULL, "RDP standard security encryption methods" }, { "f", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Fullscreen mode (++ toggles fullscreen)" }, - { "fast-path", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Enable fast-path input/output" }, - { "fipsmode", COMMAND_LINE_VALUE_BOOL, NULL, NULL, NULL, -1, NULL, "Enable FIPS mode" }, - { "fonts", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Enable smooth fonts (ClearType)" }, + { "fast-path", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "fast-path input/output" }, + { "fipsmode", COMMAND_LINE_VALUE_BOOL, NULL, NULL, NULL, -1, NULL, "FIPS mode" }, + { "floatbar", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "floatbar in fullscreen mode" }, + { "fonts", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "smooth fonts (ClearType)" }, { "frame-ack", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Number of frame acknowledgement" }, { "from-stdin", COMMAND_LINE_VALUE_OPTIONAL, "force", NULL, NULL, -1, NULL, "Read credentials from stdin. With the prompt is done before connection, otherwise on server request." }, { "g", COMMAND_LINE_VALUE_REQUIRED, "[:]", NULL, NULL, -1, NULL, "Gateway Hostname" }, @@ -99,7 +99,7 @@ static COMMAND_LINE_ARGUMENT_A args[] = { "home-drive", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Redirect user home as share" }, { "ipv6", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, "6", "Prefer IPv6 AAA record over IPv4 A record"}, #if defined(WITH_JPEG) - { "jpeg", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Enable JPEG codec" }, + { "jpeg", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "JPEG codec support" }, { "jpeg-quality", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "JPEG quality" }, #endif { "kbd", COMMAND_LINE_VALUE_REQUIRED, "0x or ", NULL, NULL, -1, NULL, "Keyboard layout" }, @@ -112,7 +112,7 @@ static COMMAND_LINE_ARGUMENT_A args[] = { "log-level", COMMAND_LINE_VALUE_REQUIRED, "OFF|FATAL|ERROR|WARN|INFO|DEBUG|TRACE", NULL, NULL, -1, NULL, "Set the default log level, see wLog(7) for details" }, { "max-fast-path-size", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Specify maximum fast-path update size" }, { "max-loop-time", COMMAND_LINE_VALUE_REQUIRED, "