Initial commit - from Precise source
authorAlex Bligh <alex@alex.org.uk>
Fri, 14 Sep 2012 11:11:27 +0000 (12:11 +0100)
committerAlex Bligh <alex@alex.org.uk>
Fri, 14 Sep 2012 11:11:27 +0000 (12:11 +0100)
524 files changed:
.gitignore [new file with mode: 0644]
.pc/.quilt_patches [new file with mode: 0644]
.pc/.quilt_series [new file with mode: 0644]
.pc/.version [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
LICENSE [new file with mode: 0644]
README [new file with mode: 0644]
channels/CMakeLists.txt [new file with mode: 0644]
channels/cliprdr/CMakeLists.txt [new file with mode: 0644]
channels/cliprdr/cliprdr_constants.h [new file with mode: 0644]
channels/cliprdr/cliprdr_format.c [new file with mode: 0644]
channels/cliprdr/cliprdr_format.h [new file with mode: 0644]
channels/cliprdr/cliprdr_main.c [new file with mode: 0644]
channels/cliprdr/cliprdr_main.h [new file with mode: 0644]
channels/drdynvc/CMakeLists.txt [new file with mode: 0644]
channels/drdynvc/audin/CMakeLists.txt [new file with mode: 0644]
channels/drdynvc/audin/alsa/CMakeLists.txt [new file with mode: 0644]
channels/drdynvc/audin/alsa/audin_alsa.c [new file with mode: 0644]
channels/drdynvc/audin/audin_main.c [new file with mode: 0644]
channels/drdynvc/audin/audin_main.h [new file with mode: 0644]
channels/drdynvc/audin/pulse/CMakeLists.txt [new file with mode: 0644]
channels/drdynvc/audin/pulse/audin_pulse.c [new file with mode: 0644]
channels/drdynvc/drdynvc_main.c [new file with mode: 0644]
channels/drdynvc/drdynvc_main.h [new file with mode: 0644]
channels/drdynvc/drdynvc_types.h [new file with mode: 0644]
channels/drdynvc/dvcman.c [new file with mode: 0644]
channels/drdynvc/dvcman.h [new file with mode: 0644]
channels/drdynvc/tsmf/CMakeLists.txt [new file with mode: 0644]
channels/drdynvc/tsmf/alsa/CMakeLists.txt [new file with mode: 0644]
channels/drdynvc/tsmf/alsa/tsmf_alsa.c [new file with mode: 0644]
channels/drdynvc/tsmf/ffmpeg/CMakeLists.txt [new file with mode: 0644]
channels/drdynvc/tsmf/ffmpeg/tsmf_ffmpeg.c [new file with mode: 0644]
channels/drdynvc/tsmf/pulse/CMakeLists.txt [new file with mode: 0644]
channels/drdynvc/tsmf/pulse/tsmf_pulse.c [new file with mode: 0644]
channels/drdynvc/tsmf/tsmf_audio.c [new file with mode: 0644]
channels/drdynvc/tsmf/tsmf_audio.h [new file with mode: 0644]
channels/drdynvc/tsmf/tsmf_codec.c [new file with mode: 0644]
channels/drdynvc/tsmf/tsmf_codec.h [new file with mode: 0644]
channels/drdynvc/tsmf/tsmf_constants.h [new file with mode: 0644]
channels/drdynvc/tsmf/tsmf_decoder.c [new file with mode: 0644]
channels/drdynvc/tsmf/tsmf_decoder.h [new file with mode: 0644]
channels/drdynvc/tsmf/tsmf_ifman.c [new file with mode: 0644]
channels/drdynvc/tsmf/tsmf_ifman.h [new file with mode: 0644]
channels/drdynvc/tsmf/tsmf_main.c [new file with mode: 0644]
channels/drdynvc/tsmf/tsmf_main.h [new file with mode: 0644]
channels/drdynvc/tsmf/tsmf_media.c [new file with mode: 0644]
channels/drdynvc/tsmf/tsmf_media.h [new file with mode: 0644]
channels/drdynvc/tsmf/tsmf_types.h [new file with mode: 0644]
channels/rail/CMakeLists.txt [new file with mode: 0644]
channels/rail/rail_main.c [new file with mode: 0644]
channels/rail/rail_main.h [new file with mode: 0644]
channels/rail/rail_orders.c [new file with mode: 0644]
channels/rail/rail_orders.h [new file with mode: 0644]
channels/rdpdbg/CMakeLists.txt [new file with mode: 0644]
channels/rdpdbg/rdpdbg_main.c [new file with mode: 0644]
channels/rdpdr/CMakeLists.txt [new file with mode: 0644]
channels/rdpdr/devman.c [new file with mode: 0644]
channels/rdpdr/devman.h [new file with mode: 0644]
channels/rdpdr/disk/CMakeLists.txt [new file with mode: 0644]
channels/rdpdr/disk/disk_file.c [new file with mode: 0644]
channels/rdpdr/disk/disk_file.h [new file with mode: 0644]
channels/rdpdr/disk/disk_main.c [new file with mode: 0644]
channels/rdpdr/irp.c [new file with mode: 0644]
channels/rdpdr/irp.h [new file with mode: 0644]
channels/rdpdr/parallel/CMakeLists.txt [new file with mode: 0644]
channels/rdpdr/parallel/parallel_main.c [new file with mode: 0644]
channels/rdpdr/printer/CMakeLists.txt [new file with mode: 0644]
channels/rdpdr/printer/printer_cups.c [new file with mode: 0644]
channels/rdpdr/printer/printer_cups.h [new file with mode: 0644]
channels/rdpdr/printer/printer_main.c [new file with mode: 0644]
channels/rdpdr/printer/printer_main.h [new file with mode: 0644]
channels/rdpdr/rdpdr_capabilities.c [new file with mode: 0644]
channels/rdpdr/rdpdr_capabilities.h [new file with mode: 0644]
channels/rdpdr/rdpdr_constants.h [new file with mode: 0644]
channels/rdpdr/rdpdr_main.c [new file with mode: 0644]
channels/rdpdr/rdpdr_main.h [new file with mode: 0644]
channels/rdpdr/rdpdr_types.h [new file with mode: 0644]
channels/rdpdr/serial/CMakeLists.txt [new file with mode: 0644]
channels/rdpdr/serial/serial_constants.h [new file with mode: 0644]
channels/rdpdr/serial/serial_main.c [new file with mode: 0644]
channels/rdpdr/serial/serial_tty.c [new file with mode: 0644]
channels/rdpdr/serial/serial_tty.h [new file with mode: 0644]
channels/rdpdr/smartcard/CMakeLists.txt [new file with mode: 0644]
channels/rdpdr/smartcard/scard_main.c [new file with mode: 0644]
channels/rdpdr/smartcard/scard_main.h [new file with mode: 0644]
channels/rdpdr/smartcard/scard_operations.c [new file with mode: 0644]
channels/rdpsnd/CMakeLists.txt [new file with mode: 0644]
channels/rdpsnd/alsa/CMakeLists.txt [new file with mode: 0644]
channels/rdpsnd/alsa/rdpsnd_alsa.c [new file with mode: 0644]
channels/rdpsnd/pulse/CMakeLists.txt [new file with mode: 0644]
channels/rdpsnd/pulse/rdpsnd_pulse.c [new file with mode: 0644]
channels/rdpsnd/rdpsnd_main.c [new file with mode: 0644]
channels/rdpsnd/rdpsnd_main.h [new file with mode: 0644]
client/CMakeLists.txt [new file with mode: 0644]
client/DirectFB/CMakeLists.txt [new file with mode: 0644]
client/DirectFB/df_event.c [new file with mode: 0644]
client/DirectFB/df_event.h [new file with mode: 0644]
client/DirectFB/df_graphics.c [new file with mode: 0644]
client/DirectFB/df_graphics.h [new file with mode: 0644]
client/DirectFB/dfreerdp.c [new file with mode: 0644]
client/DirectFB/dfreerdp.h [new file with mode: 0644]
client/Windows/CMakeLists.txt [new file with mode: 0644]
client/Windows/wf_event.c [new file with mode: 0644]
client/Windows/wf_event.h [new file with mode: 0644]
client/Windows/wf_gdi.c [new file with mode: 0644]
client/Windows/wf_gdi.h [new file with mode: 0644]
client/Windows/wf_graphics.c [new file with mode: 0644]
client/Windows/wf_graphics.h [new file with mode: 0644]
client/Windows/wfreerdp.c [new file with mode: 0644]
client/Windows/wfreerdp.h [new file with mode: 0644]
client/X11/CMakeLists.txt [new file with mode: 0644]
client/X11/xf_cliprdr.c [new file with mode: 0644]
client/X11/xf_cliprdr.h [new file with mode: 0644]
client/X11/xf_event.c [new file with mode: 0644]
client/X11/xf_event.h [new file with mode: 0644]
client/X11/xf_gdi.c [new file with mode: 0644]
client/X11/xf_gdi.h [new file with mode: 0644]
client/X11/xf_graphics.c [new file with mode: 0644]
client/X11/xf_graphics.h [new file with mode: 0644]
client/X11/xf_keyboard.c [new file with mode: 0644]
client/X11/xf_keyboard.h [new file with mode: 0644]
client/X11/xf_monitor.c [new file with mode: 0644]
client/X11/xf_monitor.h [new file with mode: 0644]
client/X11/xf_rail.c [new file with mode: 0644]
client/X11/xf_rail.h [new file with mode: 0644]
client/X11/xf_tsmf.c [new file with mode: 0644]
client/X11/xf_tsmf.h [new file with mode: 0644]
client/X11/xf_window.c [new file with mode: 0644]
client/X11/xf_window.h [new file with mode: 0644]
client/X11/xfreerdp.1.xml [new file with mode: 0644]
client/X11/xfreerdp.c [new file with mode: 0644]
client/X11/xfreerdp.h [new file with mode: 0644]
client/test/CMakeLists.txt [new file with mode: 0644]
client/test/freerdp.c [new file with mode: 0644]
cmake/AutoVersioning.cmake [new file with mode: 0644]
cmake/ConfigOptions.cmake [new file with mode: 0644]
cmake/FindCUnit.cmake [new file with mode: 0644]
cmake/FindDirectFB.cmake [new file with mode: 0644]
cmake/FindFFmpeg.cmake [new file with mode: 0644]
cmake/FindOptionalPackage.cmake [new file with mode: 0644]
cmake/FindPCSC.cmake [new file with mode: 0644]
cmake/FindPulseAudio.cmake [new file with mode: 0644]
cmake/FindX11.cmake [new file with mode: 0644]
cmake/FindXKBFile.cmake [new file with mode: 0644]
cmake/FindXShm.cmake [new file with mode: 0644]
cmake/FindXTest.cmake [new file with mode: 0644]
cmake/FindXcursor.cmake [new file with mode: 0644]
cmake/FindXdamage.cmake [new file with mode: 0644]
cmake/FindXext.cmake [new file with mode: 0644]
cmake/FindXfixes.cmake [new file with mode: 0644]
cmake/FindXinerama.cmake [new file with mode: 0644]
cmake/FindXmlto.cmake [new file with mode: 0644]
cmake/FindXv.cmake [new file with mode: 0644]
cmake/GNUInstallDirsWrapper.cmake [new file with mode: 0644]
config.h.in [new file with mode: 0644]
cunit/CMakeLists.txt [new file with mode: 0644]
cunit/test_ber.c [new file with mode: 0644]
cunit/test_ber.h [new file with mode: 0644]
cunit/test_bitmap.c [new file with mode: 0644]
cunit/test_bitmap.h [new file with mode: 0644]
cunit/test_channels.c [new file with mode: 0644]
cunit/test_channels.h [new file with mode: 0644]
cunit/test_cliprdr.c [new file with mode: 0644]
cunit/test_cliprdr.h [new file with mode: 0644]
cunit/test_color.c [new file with mode: 0644]
cunit/test_color.h [new file with mode: 0644]
cunit/test_drdynvc.c [new file with mode: 0644]
cunit/test_drdynvc.h [new file with mode: 0644]
cunit/test_freerdp.c [new file with mode: 0644]
cunit/test_freerdp.h [new file with mode: 0644]
cunit/test_gcc.c [new file with mode: 0644]
cunit/test_gcc.h [new file with mode: 0644]
cunit/test_libgdi.c [new file with mode: 0644]
cunit/test_libgdi.h [new file with mode: 0644]
cunit/test_librfx.c [new file with mode: 0644]
cunit/test_librfx.h [new file with mode: 0644]
cunit/test_license.c [new file with mode: 0644]
cunit/test_license.h [new file with mode: 0644]
cunit/test_list.c [new file with mode: 0644]
cunit/test_list.h [new file with mode: 0644]
cunit/test_mcs.c [new file with mode: 0644]
cunit/test_mcs.h [new file with mode: 0644]
cunit/test_mppc.c [new file with mode: 0644]
cunit/test_mppc.h [new file with mode: 0644]
cunit/test_orders.c [new file with mode: 0644]
cunit/test_orders.h [new file with mode: 0644]
cunit/test_pcap.c [new file with mode: 0644]
cunit/test_pcap.h [new file with mode: 0644]
cunit/test_per.c [new file with mode: 0644]
cunit/test_per.h [new file with mode: 0644]
cunit/test_rail.c [new file with mode: 0644]
cunit/test_rail.h [new file with mode: 0644]
cunit/test_stream.c [new file with mode: 0644]
cunit/test_stream.h [new file with mode: 0644]
cunit/test_utils.c [new file with mode: 0644]
cunit/test_utils.h [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/compat [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/freerdp-x11.install [new file with mode: 0644]
debian/libfreerdp-dev.install [new file with mode: 0644]
debian/libfreerdp-plugins-standard.install [new file with mode: 0644]
debian/libfreerdp1.install [new file with mode: 0644]
debian/libfreerdp1.symbols [new file with mode: 0644]
debian/rules [new file with mode: 0755]
debian/source/format [new file with mode: 0644]
debian/watch [new file with mode: 0644]
docs/Doxyfile [new file with mode: 0644]
docs/FreeRDP.vsd [new file with mode: 0644]
freerdp.pc.in [new file with mode: 0644]
freerdp.spec [new file with mode: 0644]
include/CMakeLists.txt [new file with mode: 0644]
include/freerdp/altsec.h [new file with mode: 0644]
include/freerdp/api.h [new file with mode: 0644]
include/freerdp/cache/bitmap.h [new file with mode: 0644]
include/freerdp/cache/brush.h [new file with mode: 0644]
include/freerdp/cache/cache.h [new file with mode: 0644]
include/freerdp/cache/glyph.h [new file with mode: 0644]
include/freerdp/cache/offscreen.h [new file with mode: 0644]
include/freerdp/cache/palette.h [new file with mode: 0644]
include/freerdp/cache/pointer.h [new file with mode: 0644]
include/freerdp/channels/channels.h [new file with mode: 0644]
include/freerdp/channels/wtsvc.h [new file with mode: 0644]
include/freerdp/codec/bitmap.h [new file with mode: 0644]
include/freerdp/codec/color.h [new file with mode: 0644]
include/freerdp/codec/nsc.h [new file with mode: 0644]
include/freerdp/codec/rfx.h [new file with mode: 0644]
include/freerdp/constants.h [new file with mode: 0644]
include/freerdp/dvc.h [new file with mode: 0644]
include/freerdp/extension.h [new file with mode: 0644]
include/freerdp/freerdp.h [new file with mode: 0644]
include/freerdp/gdi/16bpp.h [new file with mode: 0644]
include/freerdp/gdi/32bpp.h [new file with mode: 0644]
include/freerdp/gdi/8bpp.h [new file with mode: 0644]
include/freerdp/gdi/bitmap.h [new file with mode: 0644]
include/freerdp/gdi/brush.h [new file with mode: 0644]
include/freerdp/gdi/clipping.h [new file with mode: 0644]
include/freerdp/gdi/dc.h [new file with mode: 0644]
include/freerdp/gdi/drawing.h [new file with mode: 0644]
include/freerdp/gdi/gdi.h [new file with mode: 0644]
include/freerdp/gdi/line.h [new file with mode: 0644]
include/freerdp/gdi/palette.h [new file with mode: 0644]
include/freerdp/gdi/pen.h [new file with mode: 0644]
include/freerdp/gdi/region.h [new file with mode: 0644]
include/freerdp/gdi/shape.h [new file with mode: 0644]
include/freerdp/graphics.h [new file with mode: 0644]
include/freerdp/input.h [new file with mode: 0644]
include/freerdp/kbd/kbd.h [new file with mode: 0644]
include/freerdp/kbd/layouts.h [new file with mode: 0644]
include/freerdp/kbd/locales.h [new file with mode: 0644]
include/freerdp/kbd/vkcodes.h [new file with mode: 0644]
include/freerdp/listener.h [new file with mode: 0644]
include/freerdp/peer.h [new file with mode: 0644]
include/freerdp/plugins/cliprdr.h [new file with mode: 0644]
include/freerdp/plugins/tsmf.h [new file with mode: 0644]
include/freerdp/pointer.h [new file with mode: 0644]
include/freerdp/primary.h [new file with mode: 0644]
include/freerdp/rail.h [new file with mode: 0644]
include/freerdp/rail/icon.h [new file with mode: 0644]
include/freerdp/rail/rail.h [new file with mode: 0644]
include/freerdp/rail/window.h [new file with mode: 0644]
include/freerdp/rail/window_list.h [new file with mode: 0644]
include/freerdp/secondary.h [new file with mode: 0644]
include/freerdp/settings.h [new file with mode: 0644]
include/freerdp/svc.h [new file with mode: 0644]
include/freerdp/types.h [new file with mode: 0644]
include/freerdp/update.h [new file with mode: 0644]
include/freerdp/utils/args.h [new file with mode: 0644]
include/freerdp/utils/bitmap.h [new file with mode: 0644]
include/freerdp/utils/blob.h [new file with mode: 0644]
include/freerdp/utils/debug.h [new file with mode: 0644]
include/freerdp/utils/dsp.h [new file with mode: 0644]
include/freerdp/utils/event.h [new file with mode: 0644]
include/freerdp/utils/file.h [new file with mode: 0644]
include/freerdp/utils/hexdump.h [new file with mode: 0644]
include/freerdp/utils/list.h [new file with mode: 0644]
include/freerdp/utils/load_plugin.h [new file with mode: 0644]
include/freerdp/utils/memory.h [new file with mode: 0644]
include/freerdp/utils/mutex.h [new file with mode: 0644]
include/freerdp/utils/passphrase.h [new file with mode: 0644]
include/freerdp/utils/pcap.h [new file with mode: 0644]
include/freerdp/utils/print.h [new file with mode: 0644]
include/freerdp/utils/profiler.h [new file with mode: 0644]
include/freerdp/utils/rail.h [new file with mode: 0644]
include/freerdp/utils/rect.h [new file with mode: 0644]
include/freerdp/utils/registry.h [new file with mode: 0644]
include/freerdp/utils/semaphore.h [new file with mode: 0644]
include/freerdp/utils/signal.h [new file with mode: 0644]
include/freerdp/utils/sleep.h [new file with mode: 0644]
include/freerdp/utils/stopwatch.h [new file with mode: 0644]
include/freerdp/utils/stream.h [new file with mode: 0644]
include/freerdp/utils/string.h [new file with mode: 0644]
include/freerdp/utils/svc_plugin.h [new file with mode: 0644]
include/freerdp/utils/thread.h [new file with mode: 0644]
include/freerdp/utils/unicode.h [new file with mode: 0644]
include/freerdp/utils/wait_obj.h [new file with mode: 0644]
include/freerdp/window.h [new file with mode: 0644]
keymaps/CMakeLists.txt [new file with mode: 0644]
keymaps/aliases [new file with mode: 0644]
keymaps/amiga [new file with mode: 0644]
keymaps/ataritt [new file with mode: 0644]
keymaps/digital_vndr/lk [new file with mode: 0644]
keymaps/digital_vndr/pc [new file with mode: 0644]
keymaps/empty [new file with mode: 0644]
keymaps/evdev [new file with mode: 0644]
keymaps/fujitsu [new file with mode: 0644]
keymaps/hp [new file with mode: 0644]
keymaps/ibm [new file with mode: 0644]
keymaps/macintosh [new file with mode: 0644]
keymaps/macosx [new file with mode: 0644]
keymaps/sgi_vndr/indigo [new file with mode: 0644]
keymaps/sgi_vndr/indy [new file with mode: 0644]
keymaps/sgi_vndr/iris [new file with mode: 0644]
keymaps/sony [new file with mode: 0644]
keymaps/sun [new file with mode: 0644]
keymaps/xfree86 [new file with mode: 0644]
keymaps/xfree98 [new file with mode: 0644]
keymaps/xkb.pl [new file with mode: 0755]
libfreerdp-cache/CMakeLists.txt [new file with mode: 0644]
libfreerdp-cache/bitmap.c [new file with mode: 0644]
libfreerdp-cache/brush.c [new file with mode: 0644]
libfreerdp-cache/cache.c [new file with mode: 0644]
libfreerdp-cache/glyph.c [new file with mode: 0644]
libfreerdp-cache/offscreen.c [new file with mode: 0644]
libfreerdp-cache/palette.c [new file with mode: 0644]
libfreerdp-cache/pointer.c [new file with mode: 0644]
libfreerdp-channels/CMakeLists.txt [new file with mode: 0644]
libfreerdp-channels/libchannels.c [new file with mode: 0644]
libfreerdp-channels/libchannels.h [new file with mode: 0644]
libfreerdp-channels/wtsvc.c [new file with mode: 0644]
libfreerdp-channels/wtsvc.h [new file with mode: 0644]
libfreerdp-codec/CMakeLists.txt [new file with mode: 0644]
libfreerdp-codec/bitmap.c [new file with mode: 0644]
libfreerdp-codec/color.c [new file with mode: 0644]
libfreerdp-codec/include/bitmap.c [new file with mode: 0644]
libfreerdp-codec/nsc.c [new file with mode: 0644]
libfreerdp-codec/rfx.c [new file with mode: 0644]
libfreerdp-codec/rfx_bitstream.h [new file with mode: 0644]
libfreerdp-codec/rfx_constants.h [new file with mode: 0644]
libfreerdp-codec/rfx_decode.c [new file with mode: 0644]
libfreerdp-codec/rfx_decode.h [new file with mode: 0644]
libfreerdp-codec/rfx_differential.c [new file with mode: 0644]
libfreerdp-codec/rfx_differential.h [new file with mode: 0644]
libfreerdp-codec/rfx_dwt.c [new file with mode: 0644]
libfreerdp-codec/rfx_dwt.h [new file with mode: 0644]
libfreerdp-codec/rfx_encode.c [new file with mode: 0644]
libfreerdp-codec/rfx_encode.h [new file with mode: 0644]
libfreerdp-codec/rfx_neon.c [new file with mode: 0644]
libfreerdp-codec/rfx_neon.h [new file with mode: 0644]
libfreerdp-codec/rfx_pool.c [new file with mode: 0644]
libfreerdp-codec/rfx_pool.h [new file with mode: 0644]
libfreerdp-codec/rfx_quantization.c [new file with mode: 0644]
libfreerdp-codec/rfx_quantization.h [new file with mode: 0644]
libfreerdp-codec/rfx_rlgr.c [new file with mode: 0644]
libfreerdp-codec/rfx_rlgr.h [new file with mode: 0644]
libfreerdp-codec/rfx_sse2.c [new file with mode: 0644]
libfreerdp-codec/rfx_sse2.h [new file with mode: 0644]
libfreerdp-codec/rfx_types.h [new file with mode: 0644]
libfreerdp-core/CMakeLists.txt [new file with mode: 0644]
libfreerdp-core/activation.c [new file with mode: 0644]
libfreerdp-core/activation.h [new file with mode: 0644]
libfreerdp-core/ber.c [new file with mode: 0644]
libfreerdp-core/ber.h [new file with mode: 0644]
libfreerdp-core/capabilities.c [new file with mode: 0644]
libfreerdp-core/capabilities.h [new file with mode: 0644]
libfreerdp-core/certificate.c [new file with mode: 0644]
libfreerdp-core/certificate.h [new file with mode: 0644]
libfreerdp-core/channel.c [new file with mode: 0644]
libfreerdp-core/channel.h [new file with mode: 0644]
libfreerdp-core/connection.c [new file with mode: 0644]
libfreerdp-core/connection.h [new file with mode: 0644]
libfreerdp-core/credssp.c [new file with mode: 0644]
libfreerdp-core/credssp.h [new file with mode: 0644]
libfreerdp-core/crypto.c [new file with mode: 0644]
libfreerdp-core/crypto.h [new file with mode: 0644]
libfreerdp-core/errinfo.c [new file with mode: 0644]
libfreerdp-core/errinfo.h [new file with mode: 0644]
libfreerdp-core/extension.c [new file with mode: 0644]
libfreerdp-core/extension.h [new file with mode: 0644]
libfreerdp-core/fastpath.c [new file with mode: 0644]
libfreerdp-core/fastpath.h [new file with mode: 0644]
libfreerdp-core/freerdp.c [new file with mode: 0644]
libfreerdp-core/gcc.c [new file with mode: 0644]
libfreerdp-core/gcc.h [new file with mode: 0644]
libfreerdp-core/graphics.c [new file with mode: 0644]
libfreerdp-core/info.c [new file with mode: 0644]
libfreerdp-core/info.h [new file with mode: 0644]
libfreerdp-core/input.c [new file with mode: 0644]
libfreerdp-core/input.h [new file with mode: 0644]
libfreerdp-core/license.c [new file with mode: 0644]
libfreerdp-core/license.h [new file with mode: 0644]
libfreerdp-core/listener.c [new file with mode: 0644]
libfreerdp-core/listener.h [new file with mode: 0644]
libfreerdp-core/mcs.c [new file with mode: 0644]
libfreerdp-core/mcs.h [new file with mode: 0644]
libfreerdp-core/mppc.c [new file with mode: 0644]
libfreerdp-core/mppc.h [new file with mode: 0644]
libfreerdp-core/nego.c [new file with mode: 0644]
libfreerdp-core/nego.h [new file with mode: 0644]
libfreerdp-core/ntlmssp.c [new file with mode: 0644]
libfreerdp-core/ntlmssp.h [new file with mode: 0644]
libfreerdp-core/orders.c [new file with mode: 0644]
libfreerdp-core/orders.h [new file with mode: 0644]
libfreerdp-core/peer.c [new file with mode: 0644]
libfreerdp-core/peer.h [new file with mode: 0644]
libfreerdp-core/per.c [new file with mode: 0644]
libfreerdp-core/per.h [new file with mode: 0644]
libfreerdp-core/rdp.c [new file with mode: 0644]
libfreerdp-core/rdp.h [new file with mode: 0644]
libfreerdp-core/redirection.c [new file with mode: 0644]
libfreerdp-core/redirection.h [new file with mode: 0644]
libfreerdp-core/security.c [new file with mode: 0644]
libfreerdp-core/security.h [new file with mode: 0644]
libfreerdp-core/settings.c [new file with mode: 0644]
libfreerdp-core/surface.c [new file with mode: 0644]
libfreerdp-core/surface.h [new file with mode: 0644]
libfreerdp-core/tcp.c [new file with mode: 0644]
libfreerdp-core/tcp.h [new file with mode: 0644]
libfreerdp-core/tls.c [new file with mode: 0644]
libfreerdp-core/tls.h [new file with mode: 0644]
libfreerdp-core/tpdu.c [new file with mode: 0644]
libfreerdp-core/tpdu.h [new file with mode: 0644]
libfreerdp-core/tpkt.c [new file with mode: 0644]
libfreerdp-core/tpkt.h [new file with mode: 0644]
libfreerdp-core/transport.c [new file with mode: 0644]
libfreerdp-core/transport.h [new file with mode: 0644]
libfreerdp-core/update.c [new file with mode: 0644]
libfreerdp-core/update.h [new file with mode: 0644]
libfreerdp-core/window.c [new file with mode: 0644]
libfreerdp-core/window.h [new file with mode: 0644]
libfreerdp-gdi/16bpp.c [new file with mode: 0644]
libfreerdp-gdi/32bpp.c [new file with mode: 0644]
libfreerdp-gdi/8bpp.c [new file with mode: 0644]
libfreerdp-gdi/CMakeLists.txt [new file with mode: 0644]
libfreerdp-gdi/bitmap.c [new file with mode: 0644]
libfreerdp-gdi/brush.c [new file with mode: 0644]
libfreerdp-gdi/clipping.c [new file with mode: 0644]
libfreerdp-gdi/dc.c [new file with mode: 0644]
libfreerdp-gdi/drawing.c [new file with mode: 0644]
libfreerdp-gdi/gdi.c [new file with mode: 0644]
libfreerdp-gdi/gdi.h [new file with mode: 0644]
libfreerdp-gdi/graphics.c [new file with mode: 0644]
libfreerdp-gdi/graphics.h [new file with mode: 0644]
libfreerdp-gdi/include/line.c [new file with mode: 0644]
libfreerdp-gdi/line.c [new file with mode: 0644]
libfreerdp-gdi/palette.c [new file with mode: 0644]
libfreerdp-gdi/pen.c [new file with mode: 0644]
libfreerdp-gdi/region.c [new file with mode: 0644]
libfreerdp-gdi/shape.c [new file with mode: 0644]
libfreerdp-kbd/CMakeLists.txt [new file with mode: 0644]
libfreerdp-kbd/layouts.c [new file with mode: 0644]
libfreerdp-kbd/layouts_xkb.c [new file with mode: 0644]
libfreerdp-kbd/layouts_xkb.h [new file with mode: 0644]
libfreerdp-kbd/libkbd.c [new file with mode: 0644]
libfreerdp-kbd/libkbd.h [new file with mode: 0644]
libfreerdp-kbd/locales.c [new file with mode: 0644]
libfreerdp-kbd/x_layout_id_table.c [new file with mode: 0644]
libfreerdp-kbd/x_layout_id_table.h [new file with mode: 0644]
libfreerdp-rail/CMakeLists.txt [new file with mode: 0644]
libfreerdp-rail/icon.c [new file with mode: 0644]
libfreerdp-rail/librail.h [new file with mode: 0644]
libfreerdp-rail/rail.c [new file with mode: 0644]
libfreerdp-rail/window.c [new file with mode: 0644]
libfreerdp-rail/window_list.c [new file with mode: 0644]
libfreerdp-utils/CMakeLists.txt [new file with mode: 0644]
libfreerdp-utils/args.c [new file with mode: 0644]
libfreerdp-utils/bitmap.c [new file with mode: 0644]
libfreerdp-utils/blob.c [new file with mode: 0644]
libfreerdp-utils/dsp.c [new file with mode: 0644]
libfreerdp-utils/event.c [new file with mode: 0644]
libfreerdp-utils/file.c [new file with mode: 0644]
libfreerdp-utils/hexdump.c [new file with mode: 0644]
libfreerdp-utils/list.c [new file with mode: 0644]
libfreerdp-utils/load_plugin.c [new file with mode: 0644]
libfreerdp-utils/memory.c [new file with mode: 0644]
libfreerdp-utils/mutex.c [new file with mode: 0644]
libfreerdp-utils/passphrase.c [new file with mode: 0644]
libfreerdp-utils/pcap.c [new file with mode: 0644]
libfreerdp-utils/profiler.c [new file with mode: 0644]
libfreerdp-utils/rail.c [new file with mode: 0644]
libfreerdp-utils/rect.c [new file with mode: 0644]
libfreerdp-utils/registry.c [new file with mode: 0644]
libfreerdp-utils/semaphore.c [new file with mode: 0644]
libfreerdp-utils/signal.c [new file with mode: 0644]
libfreerdp-utils/sleep.c [new file with mode: 0644]
libfreerdp-utils/stopwatch.c [new file with mode: 0644]
libfreerdp-utils/stream.c [new file with mode: 0644]
libfreerdp-utils/string.c [new file with mode: 0644]
libfreerdp-utils/svc_plugin.c [new file with mode: 0644]
libfreerdp-utils/thread.c [new file with mode: 0644]
libfreerdp-utils/unicode.c [new file with mode: 0644]
libfreerdp-utils/wait_obj.c [new file with mode: 0644]
resources/FreeRDP-fav.ico [new file with mode: 0644]
resources/FreeRDP.ico [new file with mode: 0644]
resources/FreeRDP_Icon_256px.h [new file with mode: 0644]
resources/FreeRDP_Icon_256px.png [new file with mode: 0644]
resources/FreeRDP_Icon_256px.xpm [new file with mode: 0644]
resources/FreeRDP_Logo_Icon.ai [new file with mode: 0644]
resources/FreeRDP_Logo_Icon.svg [new file with mode: 0644]
resources/FreeRDP_OSX.icns [new file with mode: 0644]
resources/conv_to_ewm_prop.py [new file with mode: 0755]
server/CMakeLists.txt [new file with mode: 0644]
server/X11/CMakeLists.txt [new file with mode: 0644]
server/X11/rfx_test.pcap [new file with mode: 0644]
server/X11/server.crt [new file with mode: 0644]
server/X11/server.key [new file with mode: 0644]
server/X11/xf_encode.c [new file with mode: 0644]
server/X11/xf_encode.h [new file with mode: 0644]
server/X11/xf_event.c [new file with mode: 0644]
server/X11/xf_event.h [new file with mode: 0644]
server/X11/xf_input.c [new file with mode: 0644]
server/X11/xf_input.h [new file with mode: 0644]
server/X11/xf_peer.c [new file with mode: 0644]
server/X11/xf_peer.h [new file with mode: 0644]
server/X11/xfreerdp.c [new file with mode: 0644]
server/X11/xfreerdp.h [new file with mode: 0644]
server/test/CMakeLists.txt [new file with mode: 0644]
server/test/rfx_test.pcap [new file with mode: 0644]
server/test/server.crt [new file with mode: 0644]
server/test/server.key [new file with mode: 0644]
server/test/test_icon.ppm [new file with mode: 0644]
server/test/tfreerdp.c [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..00fb8ed
--- /dev/null
@@ -0,0 +1,49 @@
+# CMake
+CMakeFiles/
+CMakeCache.txt
+config.h
+install_manifest.txt
+CTestTestfile.cmake
+freerdp.pc
+Makefile
+cmake_install.cmake
+CPackConfig.cmake
+CPackSourceConfig.cmake
+
+# Eclipse
+*.project
+*.cproject
+*.settings
+
+# Documentation
+docs/api
+client/X11/xfreerdp.1
+
+# Mac OS X
+.DS_Store
+
+# Windows
+*.vcxproj
+*.vcxproj.*
+*.sdf
+*.sln
+*.suo
+*.opensdf
+ipch
+Debug
+
+# Binaries
+*.a
+*.so
+*.so.*
+*.dylib
+cunit/test_freerdp
+client/X11/xfreerdp
+client/test/freerdp-test
+client/DirectFB/dfreerdp
+server/test/tfreerdp-server
+server/X11/xfreerdp-server
+
+# Other
+*~
+
diff --git a/.pc/.quilt_patches b/.pc/.quilt_patches
new file mode 100644 (file)
index 0000000..6857a8d
--- /dev/null
@@ -0,0 +1 @@
+debian/patches
diff --git a/.pc/.quilt_series b/.pc/.quilt_series
new file mode 100644 (file)
index 0000000..c206706
--- /dev/null
@@ -0,0 +1 @@
+series
diff --git a/.pc/.version b/.pc/.version
new file mode 100644 (file)
index 0000000..0cfbf08
--- /dev/null
@@ -0,0 +1 @@
+2
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5399db7
--- /dev/null
@@ -0,0 +1,187 @@
+# FreeRDP: A Remote Desktop Protocol Client
+# FreeRDP cmake build script
+#
+# Copyright 2011 O.S. Systems Software Ltda.
+# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
+# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+cmake_minimum_required(VERSION 2.6)
+project(FreeRDP C)
+set(CMAKE_COLOR_MAKEFILE ON)
+
+# Include cmake modules
+include(CheckIncludeFiles)
+include(CheckLibraryExists)
+include(FindPkgConfig)
+include(TestBigEndian)
+
+# Include our extra modules
+set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
+
+include(AutoVersioning)
+include(ConfigOptions)
+include(FindOptionalPackage)
+include(CheckCCompilerFlag)
+include(GNUInstallDirsWrapper)
+
+# Soname versioning
+set(FREERDP_VERSION_MAJOR "1")
+set(FREERDP_VERSION_MINOR "0")
+set(FREERDP_VERSION_REVISION "1")
+set(FREERDP_VERSION "${FREERDP_VERSION_MAJOR}.${FREERDP_VERSION_MINOR}")
+set(FREERDP_VERSION_FULL "${FREERDP_VERSION}.${FREERDP_VERSION_REVISION}")
+
+# Default to release build type
+if(NOT CMAKE_BUILD_TYPE)
+   set(CMAKE_BUILD_TYPE "Release")
+endif()
+
+# build shared libs
+if(NOT BUILD_SHARED_LIBS)
+    set(BUILD_SHARED_LIBS ON)
+endif()
+
+# Compiler-specific flags
+if(CMAKE_COMPILER_IS_GNUCC)
+       set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
+       CHECK_C_COMPILER_FLAG (-Wno-unused-result Wno-unused-result)
+       if(Wno-unused-result)
+               set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-result")
+       endif()
+       CHECK_C_COMPILER_FLAG (-Wno-unused-but-set-variable Wno-unused-but-set-variable)
+       if(Wno-unused-but-set-variable)
+               set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-but-set-variable")
+       endif()
+       if(CMAKE_BUILD_TYPE STREQUAL "Release")
+               set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG")
+               set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
+       endif()
+       if(WITH_SSE2_TARGET)
+               set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse2")
+       endif()
+endif()
+
+if(MSVC)
+       set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Gd /MT")
+       set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /O2 /Ob2")
+       set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_X86_")
+       set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_UNICODE")
+       set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFREERDP_EXPORTS")
+       set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_CRT_SECURE_NO_WARNINGS")
+       set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWIN32_LEAN_AND_MEAN")
+       SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR})
+       SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR})
+endif()
+
+# Include files
+check_include_files(sys/param.h HAVE_SYS_PARAM_H)
+check_include_files(sys/socket.h HAVE_SYS_SOCKET_H)
+check_include_files(netdb.h HAVE_NETDB_H)
+check_include_files(fcntl.h HAVE_FCNTL_H)
+check_include_files(unistd.h HAVE_UNISTD_H)
+check_include_files(limits.h HAVE_LIMITS_H)
+check_include_files(stdint.h HAVE_STDINT_H)
+check_include_files(stdbool.h HAVE_STDBOOL_H)
+check_include_files(inttypes.h HAVE_INTTYPES_H)
+
+# Libraries that we have a hard dependency on
+find_required_package(OpenSSL)
+
+# Mac OS X
+if(APPLE)
+       include_directories(/opt/local/include)
+       link_directories(/opt/local/lib)
+       set(CMAKE_SHARED_LINKER_FLAGS "-mmacosx-version-min=10.4")
+endif()
+
+if(NOT WIN32)
+       find_required_package(ZLIB)
+       find_optional_package(PulseAudio)
+       find_optional_package(PCSC)
+       find_suggested_package(Cups)
+
+       if(NOT APPLE)
+               find_suggested_package(FFmpeg)
+               find_suggested_package(ALSA)
+       else(NOT APPLE)
+               find_optional_package(FFmpeg)
+       endif()
+endif()
+
+# Endian
+test_big_endian(BIG_ENDIAN)
+
+# Path to put keymaps
+set(FREERDP_KEYMAP_PATH "${CMAKE_INSTALL_PREFIX}/freerdp/keymaps")
+
+# Path to put plugins
+set(FREERDP_PLUGIN_PATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/freerdp")
+
+# Include directories
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+include_directories(${CMAKE_SOURCE_DIR}/include)
+
+# Configure files
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+
+# Generate pkg-config
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/freerdp.pc.in ${CMAKE_CURRENT_BINARY_DIR}/freerdp.pc @ONLY)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/freerdp.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
+
+# Build CUnit
+find_optional_package(CUnit)
+if(WITH_CUNIT)
+   enable_testing()
+   add_subdirectory(cunit)
+endif()
+
+# Sub-directories
+add_subdirectory(include)
+add_subdirectory(libfreerdp-utils)
+
+if(NOT WIN32)
+       add_subdirectory(libfreerdp-kbd)
+endif()
+
+add_subdirectory(libfreerdp-gdi)
+add_subdirectory(libfreerdp-rail)
+add_subdirectory(libfreerdp-cache)
+add_subdirectory(libfreerdp-codec)
+add_subdirectory(libfreerdp-channels)
+add_subdirectory(libfreerdp-core)
+
+if(NOT WIN32)
+       add_subdirectory(channels)
+endif()
+
+option(WITH_CLIENT "Build client binaries" ON)
+if(WITH_CLIENT)
+       add_subdirectory(client)
+endif()
+
+option(WITH_SERVER "Build server binaries" OFF)
+if(WITH_SERVER)
+       add_subdirectory(server)
+endif()
+
+add_subdirectory(keymaps)
+
+# Source package
+set(CPACK_SOURCE_IGNORE_FILES "/\\\\.git/;/\\\\.gitignore;/CMakeCache.txt")
+
+string(TOLOWER ${CMAKE_PROJECT_NAME} CMAKE_PROJECT_NAME_lower)
+set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME_lower}-${FREERDP_VERSION_FULL}")
+
+include(CPack)
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..6149261
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,118 @@
+2012-02-07     Version 1.0.1
+
+FreeRDP 1.0.1 is a maintenance release to address a certain number of
+issues found in 1.0.0. This release also brings corrective measures
+to certificate validation which were required for inclusion in Ubuntu.
+
+* Certificate Validation
+       * Improved validation logic and robustness
+       * Added validation of certificate name against hostname
+
+* Token-based Server Redirection
+       * Fixed redirection logic
+       * HAProxy load-balancer support
+
+* xfreerdp-server
+       * better event handling
+       * capture performance improvements
+
+* wfreerdp
+       * Fix RemoteFX support
+       * Fix mingw64 compilation
+
+* libfreerdp-core:
+       * Fix severe TCP sending bug
+       * Added server-side Standard RDP security
+
+2012-01-16     Version 1.0.0
+
+License:
+
+FreeRDP 1.0 is the first release of FreeRDP under the Apache License 2.0.
+The FreeRDP 1.x series is a rewrite, meaning there is no continuity with
+the previous FreeRDP 0.x series which were released under GPLv2.
+
+New Features:
+
+* RemoteFX
+       * Both encoder and decoder
+       * SSE2 and NEON optimization
+* NSCodec
+* RemoteApp
+       * Working, minor glitches
+* Multimedia Redirection
+       * ffmpeg support
+* Network Level Authentication (NLA)
+       * NTLMv2
+* Certificate validation
+* FIPS-compliant RDP security
+* new build system (cmake)
+* added official logo and icon
+
+New Architecture:
+
+* libfreerdp-core
+       * core protocol
+       * highly portable
+       * both client and server
+* libfreerdp-cache
+       * caching operations
+* libfreerdp-codec
+       * bitmap decompression
+       * codec encoding/decoding
+* libfreerdp-kbd
+       * keyboard mapping
+* libfreerdp-channels
+       * virtual channel management
+       * client and server side support
+* libfreerdp-gdi
+       * extensively unit tested
+       * portable software GDI implementation
+* libfreerdp-rail
+       * RemoteApp library
+* libfreerdp-utils
+       * shared utility library
+
+FreeRDP Clients:
+
+* client/X11 (xfreerdp)
+       * official client
+       * RemoteApp support
+       * X11 GDI implementation
+* client/DirectFB (dfreerdp)
+       * DirectFB support
+       * software-based GDI (libfreerdp-gdi)
+* client/Windows (wfreerdp)
+       * Native Win32 support
+
+FreeRDP Servers (experimental):
+
+* server/X11 (xfreerdp-server)
+       * RemoteFX-only
+       * no authentication
+       * highly experimental
+       * keyboard and mouse input supported
+
+Virtual Channels:
+
+* cliprdr (Clipboard Redirection)
+* rail (RemoteApp)
+* drdynvc (Dynamic Virtual Channels)
+       * audin (Audio Input Redirection)
+               * alsa support
+               * pulse support
+       * tsmf (Multimedia Redirection)
+               * alsa support
+               * pulse support
+               * ffmpeg support
+* rdpdr (Device Redirection)
+       * disk (Disk Redirection)
+       * parallel (Parallel Port Redirection)
+       * serial (Serial Port Redirection)
+       * printer (Printer Redirection)
+               * CUPS support
+       * smartcard (Smartcard Redirection)
+* rdpsnd (Sound Redirection)
+       * alsa support
+       * pulse support
+
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..d645695
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..6c67f01
--- /dev/null
+++ b/README
@@ -0,0 +1,34 @@
+FreeRDP: A Remote Desktop Protocol Implementation
+=================================================
+
+FreeRDP is a free implementation of the Remote Desktop Protocol (RDP), released under the Apache license.
+Enjoy the freedom of using your software wherever you want, the way you want it, in a world where
+interoperability can finally liberate your computing experience.
+
+Resources
+---------
+
+Website: http://www.freerdp.com/
+Wiki: https://github.com/FreeRDP/FreeRDP/wiki
+Sources: https://github.com/FreeRDP/FreeRDP/
+API doc: http://www.freerdp.com/api/
+
+IRC channel: #freerdp @ irc.freenode.net
+Mailing list: https://lists.sourceforge.net/lists/listinfo/freerdp-devel
+
+Microsoft Open Specifications
+-----------------------------
+
+Information regarding the Microsoft Open Specifications can be found at:
+http://www.microsoft.com/openspecifications/
+
+A list of reference documentation is maintained here:
+https://github.com/FreeRDP/FreeRDP/wiki/Reference-Documentation
+
+Compilation
+-----------
+
+Instructions on how to get started compiling FreeRDP can be found on the wiki:
+https://github.com/FreeRDP/FreeRDP/wiki/Compilation
+
+
diff --git a/channels/CMakeLists.txt b/channels/CMakeLists.txt
new file mode 100644 (file)
index 0000000..648e2a8
--- /dev/null
@@ -0,0 +1,26 @@
+# FreeRDP: A Remote Desktop Protocol Client
+# FreeRDP cmake build script
+#
+# Copyright 2011 O.S. Systems Software Ltda.
+# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
+# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+add_subdirectory(cliprdr)
+add_subdirectory(drdynvc)
+add_subdirectory(rdpdbg)
+add_subdirectory(rdpdr)
+add_subdirectory(rail)
+add_subdirectory(rdpsnd)
+
diff --git a/channels/cliprdr/CMakeLists.txt b/channels/cliprdr/CMakeLists.txt
new file mode 100644 (file)
index 0000000..03fb0ba
--- /dev/null
@@ -0,0 +1,33 @@
+# FreeRDP: A Remote Desktop Protocol Client
+# FreeRDP cmake build script
+#
+# Copyright 2011 O.S. Systems Software Ltda.
+# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
+# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set(CLIPRDR_SRCS
+       cliprdr_constants.h
+       cliprdr_format.c
+       cliprdr_format.h
+       cliprdr_main.c
+       cliprdr_main.h
+)
+
+add_library(cliprdr ${CLIPRDR_SRCS})
+set_target_properties(cliprdr PROPERTIES PREFIX "")
+
+target_link_libraries(cliprdr freerdp-utils)
+
+install(TARGETS cliprdr DESTINATION ${FREERDP_PLUGIN_PATH})
diff --git a/channels/cliprdr/cliprdr_constants.h b/channels/cliprdr/cliprdr_constants.h
new file mode 100644 (file)
index 0000000..d3544ba
--- /dev/null
@@ -0,0 +1,58 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Clipboard Virtual Channel
+ *
+ * Copyright 2009-2011 Jay Sorg
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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 __CLIPRDR_CONSTANTS
+#define __CLIPRDR_CONSTANTS
+
+/* CLIPRDR_HEADER.msgType */
+#define CB_MONITOR_READY               0x0001
+#define CB_FORMAT_LIST                 0x0002
+#define CB_FORMAT_LIST_RESPONSE                0x0003
+#define CB_FORMAT_DATA_REQUEST         0x0004
+#define CB_FORMAT_DATA_RESPONSE                0x0005
+#define CB_TEMP_DIRECTORY              0x0006
+#define CB_CLIP_CAPS                   0x0007
+#define CB_FILECONTENTS_REQUEST                0x0008
+#define CB_FILECONTENTS_RESPONSE       0x0009
+#define CB_LOCK_CLIPDATA               0x000A
+#define CB_UNLOCK_CLIPDATA             0x000B
+
+/* CLIPRDR_HEADER.msgFlags */
+#define CB_RESPONSE_OK                 0x0001
+#define CB_RESPONSE_FAIL               0x0002
+#define CB_ASCII_NAMES                 0x0004
+
+/* CLIPRDR_CAPS_SET.capabilitySetType */
+#define CB_CAPSTYPE_GENERAL            0x0001
+
+/* CLIPRDR_GENERAL_CAPABILITY.lengthCapability */
+#define CB_CAPSTYPE_GENERAL_LEN                12
+
+/* CLIPRDR_GENERAL_CAPABILITY.version */
+#define CB_CAPS_VERSION_1              0x00000001
+#define CB_CAPS_VERSION_2              0x00000002
+
+/* CLIPRDR_GENERAL_CAPABILITY.generalFlags */
+#define CB_USE_LONG_FORMAT_NAMES       0x00000002
+#define CB_STREAM_FILECLIP_ENABLED     0x00000004
+#define CB_FILECLIP_NO_FILE_PATHS      0x00000008
+#define CB_CAN_LOCK_CLIPDATA           0x00000010
+
+#endif /* __CLIPRDR_CONSTANTS */
diff --git a/channels/cliprdr/cliprdr_format.c b/channels/cliprdr/cliprdr_format.c
new file mode 100644 (file)
index 0000000..19099b0
--- /dev/null
@@ -0,0 +1,354 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Clipboard Virtual Channel
+ *
+ * Copyright 2009-2011 Jay Sorg
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <freerdp/types.h>
+#include <freerdp/constants.h>
+#include <freerdp/utils/hexdump.h>
+#include <freerdp/utils/memory.h>
+#include <freerdp/utils/unicode.h>
+#include <freerdp/utils/svc_plugin.h>
+#include <freerdp/plugins/cliprdr.h>
+
+#include "cliprdr_constants.h"
+#include "cliprdr_main.h"
+#include "cliprdr_format.h"
+
+#define CFSTR_HTML      "H\0T\0M\0L\0 \0F\0o\0r\0m\0a\0t\0\0"
+#define CFSTR_PNG       "P\0N\0G\0\0"
+#define CFSTR_JPEG      "J\0F\0I\0F\0\0"
+#define CFSTR_GIF       "G\0I\0F\0\0"
+
+void cliprdr_process_format_list_event(cliprdrPlugin* cliprdr, RDP_CB_FORMAT_LIST_EVENT* cb_event)
+{
+       int i;
+       STREAM* s;
+
+       DEBUG_CLIPRDR("Sending Clipboard Format List");
+
+       if (cb_event->raw_format_data)
+       {
+               s = cliprdr_packet_new(CB_FORMAT_LIST, 0, cb_event->raw_format_data_size);
+               stream_write(s, cb_event->raw_format_data, cb_event->raw_format_data_size);
+       }
+       else
+       {
+               STREAM* body = stream_new(0);
+               
+               for (i = 0; i < cb_event->num_formats; i++)
+               {
+                       const char* name;
+                       int name_length;
+
+                       switch (cb_event->formats[i])
+                       {
+                               case CB_FORMAT_HTML:
+                                       name = CFSTR_HTML; name_length = sizeof(CFSTR_HTML);
+                                       break;
+                               case CB_FORMAT_PNG:
+                                       name = CFSTR_PNG; name_length = sizeof(CFSTR_PNG);
+                                       break;
+                               case CB_FORMAT_JPEG:
+                                       name = CFSTR_JPEG; name_length = sizeof(CFSTR_JPEG);
+                                       break;
+                               case CB_FORMAT_GIF:
+                                       name = CFSTR_GIF; name_length = sizeof(CFSTR_GIF);
+                                       break;
+                               default:
+                                       name = "\0\0"; name_length = 2;
+                       }
+                       
+                       if (!cliprdr->use_long_format_names)
+                               name_length = 32;
+                       
+                       stream_extend(body, stream_get_size(body) + 4 + name_length);
+
+                       stream_write_uint32(body, cb_event->formats[i]);
+                       stream_write(body, name, name_length);
+               }
+                               
+               s = cliprdr_packet_new(CB_FORMAT_LIST, 0, stream_get_size(body));
+               stream_write(s, stream_get_head(body), stream_get_size(body));
+               stream_free(body);
+       }
+
+       cliprdr_packet_send(cliprdr, s);
+}
+
+static void cliprdr_send_format_list_response(cliprdrPlugin* cliprdr)
+{
+       STREAM* s;
+       DEBUG_CLIPRDR("Sending Clipboard Format List Response");
+       s = cliprdr_packet_new(CB_FORMAT_LIST_RESPONSE, CB_RESPONSE_OK, 0);
+       cliprdr_packet_send(cliprdr, s);
+}
+
+void cliprdr_process_short_format_names(cliprdrPlugin* cliprdr, STREAM* s, uint32 length, uint16 flags)
+{
+       int i;
+       boolean ascii;
+       int num_formats;
+       CLIPRDR_FORMAT_NAME* format_name;
+
+       num_formats = length / 36;
+
+       if (num_formats <= 0)
+       {
+               cliprdr->format_names = NULL;
+               cliprdr->num_format_names = 0;
+               return;
+       }
+
+       if (num_formats * 36 != length)
+               DEBUG_WARN("dataLen %d not divided by 36!", length);
+
+       ascii = (flags & CB_ASCII_NAMES) ? true : false;
+
+       cliprdr->format_names = (CLIPRDR_FORMAT_NAME*) xmalloc(sizeof(CLIPRDR_FORMAT_NAME) * num_formats);
+       cliprdr->num_format_names = num_formats;
+
+       for (i = 0; i < num_formats; i++)
+       {
+               format_name = &cliprdr->format_names[i];
+
+               stream_read_uint32(s, format_name->id);
+
+               if (ascii)
+               {
+                       format_name->name = xstrdup((char*) s->p);
+                       format_name->length = strlen(format_name->name);
+               }
+               else
+               {
+                       format_name->name = freerdp_uniconv_in(cliprdr->uniconv, s->p, 32);
+                       format_name->length = strlen(format_name->name);
+               }
+
+               stream_seek(s, 32);
+       }
+}
+
+void cliprdr_process_long_format_names(cliprdrPlugin* cliprdr, STREAM* s, uint32 length, uint16 flags)
+{
+       int allocated_formats = 8;
+       uint8* end_mark;
+       CLIPRDR_FORMAT_NAME* format_name;
+       
+       stream_get_mark(s, end_mark);
+       end_mark += length;
+               
+       cliprdr->format_names = (CLIPRDR_FORMAT_NAME*) xmalloc(sizeof(CLIPRDR_FORMAT_NAME) * allocated_formats);
+       cliprdr->num_format_names = 0;
+
+       while (stream_get_left(s) >= 6)
+       {
+               uint8* p;
+               int name_len;
+               
+               if (cliprdr->num_format_names >= allocated_formats)
+               {
+                       allocated_formats *= 2;
+                       cliprdr->format_names = (CLIPRDR_FORMAT_NAME*) xrealloc(cliprdr->format_names,
+                                       sizeof(CLIPRDR_FORMAT_NAME) * allocated_formats);
+               }
+               
+               format_name = &cliprdr->format_names[cliprdr->num_format_names++];
+               stream_read_uint32(s, format_name->id);
+               
+               format_name->name = NULL;
+               format_name->length = 0;
+
+               for (p = stream_get_tail(s), name_len = 0; p + 1 < end_mark; p += 2, name_len += 2)
+               {
+                       if (*((unsigned short*) p) == 0)
+                               break;
+               }
+               
+               format_name->name = freerdp_uniconv_in(cliprdr->uniconv, stream_get_tail(s), name_len);
+               format_name->length = strlen(format_name->name);
+               stream_seek(s, name_len + 2);
+       }
+}
+
+void cliprdr_process_format_list(cliprdrPlugin* cliprdr, STREAM* s, uint32 dataLen, uint16 msgFlags)
+{
+       int i;
+       uint32 format;
+       boolean supported;
+       CLIPRDR_FORMAT_NAME* format_name;
+       RDP_CB_FORMAT_LIST_EVENT* cb_event;
+
+       cb_event = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR,
+               RDP_EVENT_TYPE_CB_FORMAT_LIST, NULL, NULL);
+
+       if (dataLen > 0)
+       {
+               cb_event->raw_format_data = (uint8*) xmalloc(dataLen);
+               memcpy(cb_event->raw_format_data, stream_get_tail(s), dataLen);
+               cb_event->raw_format_data_size = dataLen;
+       }
+
+       if (cliprdr->use_long_format_names)
+               cliprdr_process_long_format_names(cliprdr, s, dataLen, msgFlags);
+       else
+               cliprdr_process_short_format_names(cliprdr, s, dataLen, msgFlags);
+
+       if (cliprdr->num_format_names > 0)
+               cb_event->formats = (uint32*) xmalloc(sizeof(uint32) * cliprdr->num_format_names);
+
+       cb_event->num_formats = 0;
+
+       for (i = 0; i < cliprdr->num_format_names; i++)
+       {
+               supported = true;
+               format_name = &cliprdr->format_names[i];
+               format = format_name->id;
+
+               switch (format)
+               {
+                       case CB_FORMAT_TEXT:
+                       case CB_FORMAT_DIB:
+                       case CB_FORMAT_UNICODETEXT:
+                               break;
+
+                       default:
+
+                               if (format_name->length > 0)
+                               {
+                                       DEBUG_CLIPRDR("format: %s", format_name->name);
+
+                                       if (strcmp(format_name->name, "HTML Format") == 0)
+                                       {
+                                               format = CB_FORMAT_HTML;
+                                               break;
+                                       }
+                                       if (strcmp(format_name->name, "PNG") == 0)
+                                       {
+                                               format = CB_FORMAT_PNG;
+                                               break;
+                                       }
+                                       if (strcmp(format_name->name, "JFIF") == 0)
+                                       {
+                                               format = CB_FORMAT_JPEG;
+                                               break;
+                                       }
+                                       if (strcmp(format_name->name, "GIF") == 0)
+                                       {
+                                               format = CB_FORMAT_GIF;
+                                               break;
+                                       }
+                               }
+                               else
+                               {
+                                       supported = false;
+                               }
+                               
+                               break;
+               }
+
+               if (supported)
+                       cb_event->formats[cb_event->num_formats++] = format;
+
+               if (format_name->length > 0)
+                       xfree(format_name->name);
+       }
+
+       xfree(cliprdr->format_names);
+       cliprdr->format_names = NULL;
+
+       cliprdr->num_format_names = 0;
+
+       svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (RDP_EVENT*) cb_event);
+       cliprdr_send_format_list_response(cliprdr);
+}
+
+void cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, STREAM* s, uint32 dataLen, uint16 msgFlags)
+{
+       /* where is this documented? */
+#if 0
+       RDP_EVENT* event;
+
+       if ((msgFlags & CB_RESPONSE_FAIL) != 0)
+       {
+               event = freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, RDP_EVENT_TYPE_CB_MONITOR_READY, NULL, NULL);
+               svc_plugin_send_event((rdpSvcPlugin*) cliprdr, event);
+       }
+#endif
+}
+
+void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, STREAM* s, uint32 dataLen, uint16 msgFlags)
+{
+       RDP_CB_DATA_REQUEST_EVENT* cb_event;
+
+       cb_event = (RDP_CB_DATA_REQUEST_EVENT*) freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR,
+               RDP_EVENT_TYPE_CB_DATA_REQUEST, NULL, NULL);
+
+       stream_read_uint32(s, cb_event->format);
+       svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (RDP_EVENT*) cb_event);
+}
+
+void cliprdr_process_format_data_response_event(cliprdrPlugin* cliprdr, RDP_CB_DATA_RESPONSE_EVENT* cb_event)
+{
+       STREAM* s;
+
+       DEBUG_CLIPRDR("Sending Format Data Response");
+
+       if (cb_event->size > 0)
+       {
+               s = cliprdr_packet_new(CB_FORMAT_DATA_RESPONSE, CB_RESPONSE_OK, cb_event->size);
+               stream_write(s, cb_event->data, cb_event->size);
+       }
+       else
+       {
+               s = cliprdr_packet_new(CB_FORMAT_DATA_RESPONSE, CB_RESPONSE_FAIL, 0);
+       }
+
+       cliprdr_packet_send(cliprdr, s);
+}
+
+void cliprdr_process_format_data_request_event(cliprdrPlugin* cliprdr, RDP_CB_DATA_REQUEST_EVENT* cb_event)
+{
+       STREAM* s;
+
+       DEBUG_CLIPRDR("Sending Format Data Request");
+
+       s = cliprdr_packet_new(CB_FORMAT_DATA_REQUEST, 0, 4);
+       stream_write_uint32(s, cb_event->format);
+       cliprdr_packet_send(cliprdr, s);
+}
+
+void cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, STREAM* s, uint32 dataLen, uint16 msgFlags)
+{
+       RDP_CB_DATA_RESPONSE_EVENT* cb_event;
+
+       cb_event = (RDP_CB_DATA_RESPONSE_EVENT*) freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR,
+               RDP_EVENT_TYPE_CB_DATA_RESPONSE, NULL, NULL);
+
+       if (dataLen > 0)
+       {
+               cb_event->size = dataLen;
+               cb_event->data = (uint8*) xmalloc(dataLen);
+               memcpy(cb_event->data, stream_get_tail(s), dataLen);
+       }
+
+       svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (RDP_EVENT*) cb_event);
+}
diff --git a/channels/cliprdr/cliprdr_format.h b/channels/cliprdr/cliprdr_format.h
new file mode 100644 (file)
index 0000000..48040b6
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Clipboard Virtual Channel
+ *
+ * Copyright 2009-2011 Jay Sorg
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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 __CLIPRDR_FORMAT_H
+#define __CLIPRDR_FORMAT_H
+
+void cliprdr_process_format_list_event(cliprdrPlugin* cliprdr, RDP_CB_FORMAT_LIST_EVENT* cb_event);
+void cliprdr_process_format_list(cliprdrPlugin* cliprdr, STREAM* s, uint32 dataLen, uint16 msgFlags);
+void cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, STREAM* s, uint32 dataLen, uint16 msgFlags);
+
+void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, STREAM* s, uint32 dataLen, uint16 msgFlags);
+void cliprdr_process_format_data_response_event(cliprdrPlugin* cliprdr, RDP_CB_DATA_RESPONSE_EVENT* cb_event);
+
+void cliprdr_process_format_data_request_event(cliprdrPlugin* cliprdr, RDP_CB_DATA_REQUEST_EVENT* cb_event);
+void cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, STREAM* s, uint32 dataLen, uint16 msgFlags);
+
+#endif /* __CLIPRDR_FORMAT_H */
diff --git a/channels/cliprdr/cliprdr_main.c b/channels/cliprdr/cliprdr_main.c
new file mode 100644 (file)
index 0000000..a2f5a79
--- /dev/null
@@ -0,0 +1,276 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Clipboard Virtual Channel
+ *
+ * Copyright 2009-2011 Jay Sorg
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <freerdp/types.h>
+#include <freerdp/constants.h>
+#include <freerdp/utils/memory.h>
+#include <freerdp/utils/unicode.h>
+#include <freerdp/utils/svc_plugin.h>
+#include <freerdp/plugins/cliprdr.h>
+
+#include "cliprdr_constants.h"
+#include "cliprdr_main.h"
+#include "cliprdr_format.h"
+
+static const char* const CB_MSG_TYPE_STRINGS[] =
+{
+       "",
+       "CB_MONITOR_READY",
+       "CB_FORMAT_LIST",
+       "CB_FORMAT_LIST_RESPONSE",
+       "CB_FORMAT_DATA_REQUEST",
+       "CB_FORMAT_DATA_RESPONSE",
+       "CB_TEMP_DIRECTORY",
+       "CB_CLIP_CAPS",
+       "CB_FILECONTENTS_REQUEST",
+       "CB_FILECONTENTS_RESPONSE",
+       "CB_LOCK_CLIPDATA"
+       "CB_UNLOCK_CLIPDATA"
+};
+
+STREAM* cliprdr_packet_new(uint16 msgType, uint16 msgFlags, uint32 dataLen)
+{
+       STREAM* s;
+
+       s = stream_new(dataLen + 8);
+       stream_write_uint16(s, msgType);
+       stream_write_uint16(s, msgFlags);
+       /* Write actual length after the entire packet has been constructed. */
+       stream_seek(s, 4);
+
+       return s;
+}
+
+void cliprdr_packet_send(cliprdrPlugin* cliprdr, STREAM* s)
+{
+       int pos;
+       uint32 dataLen;
+
+       pos = stream_get_pos(s);
+       dataLen = pos - 8;
+       stream_set_pos(s, 4);
+       stream_write_uint32(s, dataLen);
+       stream_set_pos(s, pos);
+
+       svc_plugin_send((rdpSvcPlugin*) cliprdr, s);
+}
+
+static void cliprdr_process_connect(rdpSvcPlugin* plugin)
+{
+       DEBUG_CLIPRDR("connecting");
+
+       ((cliprdrPlugin*) plugin)->uniconv = freerdp_uniconv_new();
+}
+
+void cliprdr_print_general_capability_flags(uint32 flags)
+{
+       printf("generalFlags (0x%08X) {\n", flags);
+
+       if (flags & CB_USE_LONG_FORMAT_NAMES)
+               printf("\tCB_USE_LONG_FORMAT_NAMES\n");
+       if (flags & CB_STREAM_FILECLIP_ENABLED)
+               printf("\tCB_STREAM_FILECLIP_ENABLED\n");
+       if (flags & CB_FILECLIP_NO_FILE_PATHS)
+               printf("\tCB_FILECLIP_NO_FILE_PATHS\n");
+       if (flags & CB_CAN_LOCK_CLIPDATA)
+               printf("\tCB_CAN_LOCK_CLIPDATA\n");
+
+       printf("}\n");
+}
+
+static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, STREAM* s)
+{
+       uint32 version;
+       uint32 generalFlags;
+
+       stream_read_uint32(s, version); /* version (4 bytes) */
+       stream_read_uint32(s, generalFlags); /* generalFlags (4 bytes) */
+
+       DEBUG_CLIPRDR("Version: %d", version);
+
+#ifdef WITH_DEBUG_CLIPRDR
+       cliprdr_print_general_capability_flags(generalFlags);
+#endif
+
+       if (generalFlags & CB_USE_LONG_FORMAT_NAMES)
+               cliprdr->use_long_format_names = true;
+
+       if (generalFlags & CB_STREAM_FILECLIP_ENABLED)
+               cliprdr->stream_fileclip_enabled = true;
+
+       if (generalFlags & CB_FILECLIP_NO_FILE_PATHS)
+               cliprdr->fileclip_no_file_paths = true;
+
+       if (generalFlags & CB_CAN_LOCK_CLIPDATA)
+               cliprdr->can_lock_clipdata = true;
+
+       cliprdr->received_caps = true;
+}
+
+static void cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, STREAM* s, uint16 length, uint16 flags)
+{
+       int i;
+       uint16 lengthCapability;
+       uint16 cCapabilitiesSets;
+       uint16 capabilitySetType;
+
+       stream_read_uint16(s, cCapabilitiesSets); /* cCapabilitiesSets (2 bytes) */
+       stream_seek_uint16(s); /* pad1 (2 bytes) */
+
+       DEBUG_CLIPRDR("cCapabilitiesSets %d", cCapabilitiesSets);
+
+       for (i = 0; i < cCapabilitiesSets; i++)
+       {
+               stream_read_uint16(s, capabilitySetType); /* capabilitySetType (2 bytes) */
+               stream_read_uint16(s, lengthCapability); /* lengthCapability (2 bytes) */
+
+               switch (capabilitySetType)
+               {
+                       case CB_CAPSTYPE_GENERAL:
+                               cliprdr_process_general_capability(cliprdr, s);
+                               break;
+
+                       default:
+                               DEBUG_WARN("unknown cliprdr capability set: %d", capabilitySetType);
+                               break;
+               }
+       }
+}
+
+static void cliprdr_send_clip_caps(cliprdrPlugin* cliprdr)
+{
+       STREAM* s;
+       uint32 flags;
+
+       s = cliprdr_packet_new(CB_CLIP_CAPS, 0, 4 + CB_CAPSTYPE_GENERAL_LEN);
+
+       DEBUG_CLIPRDR("Sending Capabilities");
+
+       flags = CB_USE_LONG_FORMAT_NAMES;
+
+       stream_write_uint16(s, 1); /* cCapabilitiesSets */
+       stream_write_uint16(s, 0); /* pad1 */
+       stream_write_uint16(s, CB_CAPSTYPE_GENERAL); /* capabilitySetType */
+       stream_write_uint16(s, CB_CAPSTYPE_GENERAL_LEN); /* lengthCapability */
+       stream_write_uint32(s, CB_CAPS_VERSION_2); /* version */
+       stream_write_uint32(s, flags); /* generalFlags */
+
+       cliprdr_packet_send(cliprdr, s);
+}
+
+static void cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, STREAM* s, uint16 length, uint16 flags)
+{
+       RDP_EVENT* event;
+
+       if (cliprdr->received_caps)
+               cliprdr_send_clip_caps(cliprdr);
+
+       event = freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, RDP_EVENT_TYPE_CB_MONITOR_READY, NULL, NULL);
+       svc_plugin_send_event((rdpSvcPlugin*) cliprdr, event);
+}
+
+static void cliprdr_process_receive(rdpSvcPlugin* plugin, STREAM* s)
+{
+       uint16 msgType;
+       uint16 msgFlags;
+       uint32 dataLen;
+       cliprdrPlugin* cliprdr = (cliprdrPlugin*) plugin;
+
+       stream_read_uint16(s, msgType);
+       stream_read_uint16(s, msgFlags);
+       stream_read_uint32(s, dataLen);
+
+       DEBUG_CLIPRDR("msgType: %s (%d), msgFlags: %d dataLen: %d",
+               CB_MSG_TYPE_STRINGS[msgType], msgType, msgFlags, dataLen);
+
+       switch (msgType)
+       {
+               case CB_CLIP_CAPS:
+                       cliprdr_process_clip_caps(cliprdr, s, dataLen, msgFlags);
+                       break;
+
+               case CB_MONITOR_READY:
+                       cliprdr_process_monitor_ready(cliprdr, s, dataLen, msgFlags);
+                       break;
+
+               case CB_FORMAT_LIST:
+                       cliprdr_process_format_list(cliprdr, s, dataLen, msgFlags);
+                       break;
+
+               case CB_FORMAT_LIST_RESPONSE:
+                       cliprdr_process_format_list_response(cliprdr, s, dataLen, msgFlags);
+                       break;
+
+               case CB_FORMAT_DATA_REQUEST:
+                       cliprdr_process_format_data_request(cliprdr, s, dataLen, msgFlags);
+                       break;
+
+               case CB_FORMAT_DATA_RESPONSE:
+                       cliprdr_process_format_data_response(cliprdr, s, dataLen, msgFlags);
+                       break;
+
+               default:
+                       DEBUG_WARN("unknown msgType %d", msgType);
+                       break;
+       }
+
+       stream_free(s);
+}
+
+static void cliprdr_process_event(rdpSvcPlugin* plugin, RDP_EVENT* event)
+{
+       switch (event->event_type)
+       {
+               case RDP_EVENT_TYPE_CB_FORMAT_LIST:
+                       cliprdr_process_format_list_event((cliprdrPlugin*) plugin, (RDP_CB_FORMAT_LIST_EVENT*) event);
+                       break;
+
+               case RDP_EVENT_TYPE_CB_DATA_REQUEST:
+                       cliprdr_process_format_data_request_event((cliprdrPlugin*) plugin, (RDP_CB_DATA_REQUEST_EVENT*) event);
+                       break;
+
+               case RDP_EVENT_TYPE_CB_DATA_RESPONSE:
+                       cliprdr_process_format_data_response_event((cliprdrPlugin*) plugin, (RDP_CB_DATA_RESPONSE_EVENT*) event);
+                       break;
+
+               default:
+                       DEBUG_WARN("unknown event type %d", event->event_type);
+                       break;
+       }
+
+       freerdp_event_free(event);
+}
+
+static void cliprdr_process_terminate(rdpSvcPlugin* plugin)
+{
+       cliprdrPlugin* cliprdr_plugin = (cliprdrPlugin*) plugin;
+
+       if (cliprdr_plugin->uniconv != NULL)
+               freerdp_uniconv_free(cliprdr_plugin->uniconv);
+
+       xfree(plugin);
+}
+
+DEFINE_SVC_PLUGIN(cliprdr, "cliprdr",
+       CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
+       CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL)
diff --git a/channels/cliprdr/cliprdr_main.h b/channels/cliprdr/cliprdr_main.h
new file mode 100644 (file)
index 0000000..e3059a2
--- /dev/null
@@ -0,0 +1,58 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Clipboard Virtual Channel
+ *
+ * Copyright 2009-2011 Jay Sorg
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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 __CLIPRDR_MAIN_H
+#define __CLIPRDR_MAIN_H
+
+#include <freerdp/utils/debug.h>
+#include <freerdp/utils/stream.h>
+
+struct _CLIPRDR_FORMAT_NAME
+{
+       uint32 id;
+       char* name;
+       int length;
+};
+typedef struct _CLIPRDR_FORMAT_NAME CLIPRDR_FORMAT_NAME;
+
+struct cliprdr_plugin
+{
+       rdpSvcPlugin plugin;
+       UNICONV* uniconv;
+       boolean received_caps;
+       boolean use_long_format_names;
+       boolean stream_fileclip_enabled;
+       boolean fileclip_no_file_paths;
+       boolean can_lock_clipdata;
+       CLIPRDR_FORMAT_NAME* format_names;
+       int num_format_names;
+};
+typedef struct cliprdr_plugin cliprdrPlugin;
+
+STREAM* cliprdr_packet_new(uint16 msgType, uint16 msgFlags, uint32 dataLen);
+void cliprdr_packet_send(cliprdrPlugin* cliprdr, STREAM* data_out);
+
+#ifdef WITH_DEBUG_CLIPRDR
+#define DEBUG_CLIPRDR(fmt, ...) DEBUG_CLASS(CLIPRDR, fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_CLIPRDR(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
+#endif
+
+#endif /* __CLIPRDR_MAIN_H */
diff --git a/channels/drdynvc/CMakeLists.txt b/channels/drdynvc/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1e3cc13
--- /dev/null
@@ -0,0 +1,37 @@
+# FreeRDP: A Remote Desktop Protocol Client
+# FreeRDP cmake build script
+#
+# Copyright 2011 O.S. Systems Software Ltda.
+# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
+# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set(DRDYNVC_SRCS
+       drdynvc_main.c
+       drdynvc_main.h
+       drdynvc_types.h
+       dvcman.c
+       dvcman.h
+)
+
+add_library(drdynvc ${DRDYNVC_SRCS})
+set_target_properties(drdynvc PROPERTIES PREFIX "")
+
+target_link_libraries(drdynvc freerdp-utils)
+
+install(TARGETS drdynvc DESTINATION ${FREERDP_PLUGIN_PATH})
+
+add_subdirectory(tsmf)
+add_subdirectory(audin)
+
diff --git a/channels/drdynvc/audin/CMakeLists.txt b/channels/drdynvc/audin/CMakeLists.txt
new file mode 100644 (file)
index 0000000..37fe004
--- /dev/null
@@ -0,0 +1,41 @@
+# FreeRDP: A Remote Desktop Protocol Client
+# FreeRDP cmake build script
+#
+# Copyright 2011 O.S. Systems Software Ltda.
+# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
+# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set(AUDIN_SRCS
+       audin_main.c
+       audin_main.h
+)
+
+include_directories(..)
+
+add_library(audin ${AUDIN_SRCS})
+set_target_properties(audin PROPERTIES PREFIX "")
+
+target_link_libraries(audin freerdp-utils)
+
+install(TARGETS audin DESTINATION ${FREERDP_PLUGIN_PATH})
+
+if(WITH_ALSA)
+       add_subdirectory(alsa)
+endif()
+
+if(WITH_PULSEAUDIO)
+       add_subdirectory(pulse)
+endif()
+
diff --git a/channels/drdynvc/audin/alsa/CMakeLists.txt b/channels/drdynvc/audin/alsa/CMakeLists.txt
new file mode 100644 (file)
index 0000000..786f9ce
--- /dev/null
@@ -0,0 +1,33 @@
+# FreeRDP: A Remote Desktop Protocol Client
+# FreeRDP cmake build script
+#
+# Copyright 2011 O.S. Systems Software Ltda.
+# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
+# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set(AUDIN_ALSA_SRCS
+       audin_alsa.c
+)
+
+include_directories(..)
+include_directories(${ALSA_INCLUDE_DIRS})
+
+add_library(audin_alsa ${AUDIN_ALSA_SRCS})
+set_target_properties(audin_alsa PROPERTIES PREFIX "")
+
+target_link_libraries(audin_alsa freerdp-utils)
+target_link_libraries(audin_alsa ${ALSA_LIBRARIES})
+
+install(TARGETS audin_alsa DESTINATION ${FREERDP_PLUGIN_PATH})
diff --git a/channels/drdynvc/audin/alsa/audin_alsa.c b/channels/drdynvc/audin/alsa/audin_alsa.c
new file mode 100644 (file)
index 0000000..540d184
--- /dev/null
@@ -0,0 +1,366 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Audio Input Redirection Virtual Channel - ALSA implementation
+ *
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <alsa/asoundlib.h>
+#include <freerdp/utils/memory.h>
+#include <freerdp/utils/thread.h>
+#include <freerdp/utils/dsp.h>
+
+#include "audin_main.h"
+
+typedef struct _AudinALSADevice
+{
+       IAudinDevice iface;
+
+       char device_name[32];
+       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;
+       ADPCM adpcm;
+
+       freerdp_thread* thread;
+
+       uint8* buffer;
+       int buffer_frames;
+
+       AudinReceive receive;
+       void* user_data;
+} AudinALSADevice;
+
+static boolean audin_alsa_set_params(AudinALSADevice* alsa, snd_pcm_t* capture_handle)
+{
+       int error;
+       snd_pcm_hw_params_t* hw_params;
+
+       if ((error = snd_pcm_hw_params_malloc(&hw_params)) < 0)
+       {
+               DEBUG_WARN("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_channels_near(capture_handle, hw_params,
+               &alsa->actual_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 %d / channel %d is "
+                       "different from target rate %d / channel %d, resampling required.",
+                       alsa->actual_rate, alsa->actual_channels,
+                       alsa->target_rate, alsa->target_channels);
+       }
+       return true;
+}
+
+static boolean audin_alsa_thread_receive(AudinALSADevice* alsa, uint8* src, int size)
+{
+       int frames;
+       int cframes;
+       int ret = 0;
+       int encoded_size;
+       uint8* encoded_data;
+       int rbytes_per_frame;
+       int tbytes_per_frame;
+       uint8* resampled_data;
+
+       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))
+       {
+               resampled_data = NULL;
+               frames = size / rbytes_per_frame;
+       }
+       else
+       {
+               resampled_data = dsp_resample(src, alsa->bytes_per_channel,
+                       alsa->actual_channels, alsa->actual_rate, size / rbytes_per_frame,
+                       alsa->target_channels, alsa->target_rate, &frames);
+               DEBUG_DVC("resampled %d frames at %d to %d frames at %d",
+                       size / rbytes_per_frame, alsa->actual_rate, frames, alsa->target_rate);
+               size = frames * tbytes_per_frame;
+               src = resampled_data;
+       }
+
+       while (frames > 0)
+       {
+               if (freerdp_thread_is_stopped(alsa->thread))
+                       break;
+
+               cframes = alsa->frames_per_packet - alsa->buffer_frames;
+               if (cframes > frames)
+                       cframes = frames;
+               memcpy(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 == 0x11)
+                       {
+                               encoded_data = dsp_encode_ima_adpcm(&alsa->adpcm,
+                                       alsa->buffer, alsa->buffer_frames * tbytes_per_frame,
+                                       alsa->target_channels, alsa->block_size, &encoded_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;
+                       }
+
+                       if (freerdp_thread_is_stopped(alsa->thread))
+                       {
+                               ret = 0;
+                               frames = 0;
+                       }
+                       else
+                               ret = alsa->receive(encoded_data, encoded_size, alsa->user_data);
+                       alsa->buffer_frames = 0;
+                       if (encoded_data != alsa->buffer)
+                               xfree(encoded_data);
+                       if (!ret)
+                               break;
+               }
+               src += cframes * tbytes_per_frame;
+               frames -= cframes;
+       }
+
+       if (resampled_data)
+               xfree(resampled_data);
+
+       return ret;
+}
+
+static void* audin_alsa_thread_func(void* arg)
+{
+       int error;
+       uint8* buffer;
+       int rbytes_per_frame;
+       int tbytes_per_frame;
+       snd_pcm_t* capture_handle = NULL;
+       AudinALSADevice* alsa = (AudinALSADevice*) arg;
+
+       DEBUG_DVC("in");
+
+       rbytes_per_frame = alsa->actual_channels * alsa->bytes_per_channel;
+       tbytes_per_frame = alsa->target_channels * alsa->bytes_per_channel;
+       alsa->buffer = (uint8*) xzalloc(tbytes_per_frame * alsa->frames_per_packet);
+       alsa->buffer_frames = 0;
+       buffer = (uint8*) xzalloc(rbytes_per_frame * alsa->frames_per_packet);
+       memset(&alsa->adpcm, 0, sizeof(ADPCM));
+       do
+       {
+               if ((error = snd_pcm_open(&capture_handle, alsa->device_name, SND_PCM_STREAM_CAPTURE, 0)) < 0)
+               {
+                       DEBUG_WARN("snd_pcm_open (%s)", snd_strerror(error));
+                       break;
+               }
+               if (!audin_alsa_set_params(alsa, capture_handle))
+               {
+                       break;
+               }
+
+               while (!freerdp_thread_is_stopped(alsa->thread))
+               {
+                       error = snd_pcm_readi(capture_handle, buffer, alsa->frames_per_packet);
+                       if (error == -EPIPE)
+                       {
+                               snd_pcm_recover(capture_handle, error, 0);
+                               continue;
+                       }
+                       else if (error < 0)
+                       {
+                               DEBUG_WARN("snd_pcm_readi (%s)", snd_strerror(error));
+                               break;
+                       }
+                       if (!audin_alsa_thread_receive(alsa, buffer, error * rbytes_per_frame))
+                               break;
+               }
+       } while (0);
+
+       xfree(buffer);
+       xfree(alsa->buffer);
+       alsa->buffer = NULL;
+       if (capture_handle)
+               snd_pcm_close(capture_handle);
+
+       freerdp_thread_quit(alsa->thread);
+
+       DEBUG_DVC("out");
+
+       return NULL;
+}
+
+static void audin_alsa_free(IAudinDevice* device)
+{
+       AudinALSADevice* alsa = (AudinALSADevice*) device;
+
+       freerdp_thread_free(alsa->thread);
+       xfree(alsa);
+}
+
+static boolean audin_alsa_format_supported(IAudinDevice* device, audinFormat* format)
+{
+       switch (format->wFormatTag)
+       {
+               case 1: /* PCM */
+                       if (format->cbSize == 0 &&
+                               (format->nSamplesPerSec <= 48000) &&
+                               (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) &&
+                               (format->nChannels == 1 || format->nChannels == 2))
+                       {
+                               return true;
+                       }
+                       break;
+
+               case 0x11: /* IMA ADPCM */
+                       if ((format->nSamplesPerSec <= 48000) &&
+                               (format->wBitsPerSample == 4) &&
+                               (format->nChannels == 1 || format->nChannels == 2))
+                       {
+                               return true;
+                       }
+                       break;
+       }
+       return false;
+}
+
+static void audin_alsa_set_format(IAudinDevice* device, audinFormat* 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 1: /* PCM */
+                       switch (format->wBitsPerSample)
+                       {
+                               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;
+                       }
+                       break;
+
+               case 0x11: /* IMA 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=%d",
+                               alsa->frames_per_packet);
+                       break;
+       }
+       alsa->wformat = format->wFormatTag;
+       alsa->block_size = format->nBlockAlign;
+}
+
+static void audin_alsa_open(IAudinDevice* device, AudinReceive receive, void* user_data)
+{
+       AudinALSADevice* alsa = (AudinALSADevice*) device;
+
+       DEBUG_DVC("");
+
+       alsa->receive = receive;
+       alsa->user_data = user_data;
+
+       freerdp_thread_start(alsa->thread, audin_alsa_thread_func, alsa);
+}
+
+static void audin_alsa_close(IAudinDevice* device)
+{
+       AudinALSADevice* alsa = (AudinALSADevice*) device;
+
+       DEBUG_DVC("");
+
+       freerdp_thread_stop(alsa->thread);
+
+       alsa->receive = NULL;
+       alsa->user_data = NULL;
+}
+
+int FreeRDPAudinDeviceEntry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
+{
+       AudinALSADevice* alsa;
+       RDP_PLUGIN_DATA* data;
+
+       alsa = xnew(AudinALSADevice);
+
+       alsa->iface.Open = audin_alsa_open;
+       alsa->iface.FormatSupported = audin_alsa_format_supported;
+       alsa->iface.SetFormat = audin_alsa_set_format;
+       alsa->iface.Close = audin_alsa_close;
+       alsa->iface.Free = audin_alsa_free;
+
+       data = pEntryPoints->plugin_data;
+       if (data && data->data[0] && strcmp(data->data[0], "audin") == 0 &&
+               data->data[1] && strcmp(data->data[1], "alsa") == 0)
+       {
+               if (data[2].size)
+                       strncpy(alsa->device_name, (char*)data->data[2], sizeof(alsa->device_name));
+       }
+       if (alsa->device_name[0] == '\0')
+       {
+               strcpy(alsa->device_name, "default");
+       }
+
+       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->thread = freerdp_thread_new();
+
+       pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) alsa);
+
+       return 0;
+}
+
diff --git a/channels/drdynvc/audin/audin_main.c b/channels/drdynvc/audin/audin_main.c
new file mode 100644 (file)
index 0000000..095c539
--- /dev/null
@@ -0,0 +1,544 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Audio Input Redirection Virtual Channel
+ *
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <freerdp/utils/memory.h>
+#include <freerdp/utils/stream.h>
+#include <freerdp/utils/load_plugin.h>
+
+#include "audin_main.h"
+
+#define MSG_SNDIN_VERSION       0x01
+#define MSG_SNDIN_FORMATS       0x02
+#define MSG_SNDIN_OPEN          0x03
+#define MSG_SNDIN_OPEN_REPLY    0x04
+#define MSG_SNDIN_DATA_INCOMING 0x05
+#define MSG_SNDIN_DATA          0x06
+#define MSG_SNDIN_FORMATCHANGE  0x07
+
+typedef struct _AUDIN_LISTENER_CALLBACK AUDIN_LISTENER_CALLBACK;
+struct _AUDIN_LISTENER_CALLBACK
+{
+       IWTSListenerCallback iface;
+
+       IWTSPlugin* plugin;
+       IWTSVirtualChannelManager* channel_mgr;
+};
+
+typedef struct _AUDIN_CHANNEL_CALLBACK AUDIN_CHANNEL_CALLBACK;
+struct _AUDIN_CHANNEL_CALLBACK
+{
+       IWTSVirtualChannelCallback iface;
+
+       IWTSPlugin* plugin;
+       IWTSVirtualChannelManager* channel_mgr;
+       IWTSVirtualChannel* channel;
+
+       /**
+        * The supported format list sent back to the server, which needs to
+        * be stored as reference when the server sends the format index in
+        * Open PDU and Format Change PDU
+        */
+       audinFormat* formats;
+       int formats_count;
+};
+
+typedef struct _AUDIN_PLUGIN AUDIN_PLUGIN;
+struct _AUDIN_PLUGIN
+{
+       IWTSPlugin iface;
+
+       AUDIN_LISTENER_CALLBACK* listener_callback;
+
+       /* Parsed plugin data */
+       uint16 fixed_format;
+       uint16 fixed_channel;   
+       uint32 fixed_rate;
+
+       /* Device interface */
+       IAudinDevice* device;
+};
+
+static int audin_process_version(IWTSVirtualChannelCallback* pChannelCallback, STREAM* s)
+{
+       int error;
+       STREAM* out;
+       uint32 Version;
+       AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
+
+       stream_read_uint32(s, Version);
+
+       DEBUG_DVC("Version=%d", Version);
+
+       out = stream_new(5);
+       stream_write_uint8(out, MSG_SNDIN_VERSION);
+       stream_write_uint32(out, Version);
+       error = callback->channel->Write(callback->channel, stream_get_length(s), stream_get_head(s), NULL);
+       stream_free(out);
+
+       return error;
+}
+
+static int audin_send_incoming_data_pdu(IWTSVirtualChannelCallback* pChannelCallback)
+{
+       uint8 out_data[1];
+       AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
+
+       out_data[0] = MSG_SNDIN_DATA_INCOMING;
+       return callback->channel->Write(callback->channel, 1, out_data, NULL);
+}
+
+static int audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, STREAM* s)
+{
+       AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
+       AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin;
+       uint32 i;
+       uint8* fm;
+       int error;
+       STREAM* out;
+       uint32 NumFormats;
+       audinFormat format;
+       uint32 cbSizeFormatsPacket;
+
+       stream_read_uint32(s, NumFormats);
+       DEBUG_DVC("NumFormats %d", NumFormats);
+       if ((NumFormats < 1) || (NumFormats > 1000))
+       {
+               DEBUG_WARN("bad NumFormats %d", NumFormats);
+               return 1;
+       }
+       stream_seek_uint32(s); /* cbSizeFormatsPacket */
+
+       callback->formats = (audinFormat*) xzalloc(NumFormats * sizeof(audinFormat));
+
+       out = stream_new(9);
+       stream_seek(out, 9);
+
+       /* SoundFormats (variable) */
+       for (i = 0; i < NumFormats; i++)
+       {
+               stream_get_mark(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_get_tail(s);
+               stream_seek(s, format.cbSize);
+               
+               DEBUG_DVC("wFormatTag=%d nChannels=%d nSamplesPerSec=%d "
+                       "nBlockAlign=%d wBitsPerSample=%d cbSize=%d",
+                       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))
+               {
+                       DEBUG_DVC("format ok");
+
+                       /* Store the agreed format in the corresponding index */
+                       callback->formats[callback->formats_count++] = format;
+                       /* Put the format to output buffer */
+                       stream_check_size(out, 18 + format.cbSize);
+                       stream_write(out, fm, 18 + format.cbSize);
+               }
+       }
+
+       audin_send_incoming_data_pdu(pChannelCallback);
+
+       cbSizeFormatsPacket = stream_get_pos(out);
+       stream_set_pos(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) */
+
+       error = callback->channel->Write(callback->channel, cbSizeFormatsPacket, stream_get_head(out), NULL);
+       stream_free(out);
+
+       return error;
+}
+
+static int audin_send_format_change_pdu(IWTSVirtualChannelCallback* pChannelCallback, uint32 NewFormat)
+{
+       int error;
+       STREAM* out;
+       AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
+
+       out = stream_new(5);
+       stream_write_uint8(out, MSG_SNDIN_FORMATCHANGE);
+       stream_write_uint32(out, NewFormat);
+       error = callback->channel->Write(callback->channel, 5, stream_get_head(out), NULL);
+       stream_free(out);
+
+       return error;
+}
+
+static int audin_send_open_reply_pdu(IWTSVirtualChannelCallback* pChannelCallback, uint32 Result)
+{
+       int error;
+       STREAM* out;
+       AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
+
+       out = stream_new(5);
+       stream_write_uint8(out, MSG_SNDIN_OPEN_REPLY);
+       stream_write_uint32(out, Result);
+       error = callback->channel->Write(callback->channel, 5, stream_get_head(out), NULL);
+       stream_free(out);
+
+       return error;
+}
+
+static boolean audin_receive_wave_data(uint8* data, int size, void* user_data)
+{
+       int error;
+       STREAM* out;
+       AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) user_data;
+
+       error = audin_send_incoming_data_pdu((IWTSVirtualChannelCallback*) callback);
+
+       if (error != 0)
+               return false;
+
+       out = stream_new(size + 1);
+       stream_write_uint8(out, MSG_SNDIN_DATA);
+       stream_write(out, data, size);
+       error = callback->channel->Write(callback->channel, stream_get_length(out), stream_get_head(out), NULL);
+       stream_free(out);
+
+       return (error == 0 ? true : false);
+}
+
+static int audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, STREAM* s)
+{
+       AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
+       AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin;
+       audinFormat* format;
+       uint32 initialFormat;
+       uint32 FramesPerPacket;
+
+       stream_read_uint32(s, FramesPerPacket);
+       stream_read_uint32(s, initialFormat);
+
+       DEBUG_DVC("FramesPerPacket=%d initialFormat=%d",
+               FramesPerPacket, initialFormat);
+
+       if (initialFormat >= callback->formats_count)
+       {
+               DEBUG_WARN("invalid format index %d (total %d)",
+                       initialFormat, callback->formats_count);
+               return 1;
+       }
+
+       format = &callback->formats[initialFormat];
+       if (audin->device)
+       {
+               IFCALL(audin->device->SetFormat, audin->device, format, FramesPerPacket);
+               IFCALL(audin->device->Open, audin->device, audin_receive_wave_data, callback);
+       }
+
+       audin_send_format_change_pdu(pChannelCallback, initialFormat);
+       audin_send_open_reply_pdu(pChannelCallback, 0);
+
+       return 0;
+}
+
+static int audin_process_format_change(IWTSVirtualChannelCallback* pChannelCallback, STREAM* s)
+{
+       AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
+       AUDIN_PLUGIN * audin = (AUDIN_PLUGIN*) callback->plugin;
+       uint32 NewFormat;
+       audinFormat* format;
+
+       stream_read_uint32(s, NewFormat);
+
+       DEBUG_DVC("NewFormat=%d", NewFormat);
+
+       if (NewFormat >= callback->formats_count)
+       {
+               DEBUG_WARN("invalid format index %d (total %d)",
+                       NewFormat, callback->formats_count);
+               return 1;
+       }
+
+       format = &callback->formats[NewFormat];
+
+       if (audin->device)
+       {
+               IFCALL(audin->device->Close, audin->device);
+               IFCALL(audin->device->SetFormat, audin->device, format, 0);
+               IFCALL(audin->device->Open, audin->device, audin_receive_wave_data, callback);
+       }
+
+       audin_send_format_change_pdu(pChannelCallback, NewFormat);
+
+       return 0;
+}
+
+static int audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, uint32 cbSize, uint8* pBuffer)
+{
+       int error;
+       STREAM* s;
+       uint8 MessageId;
+
+       s = stream_new(0);
+       stream_attach(s, pBuffer, cbSize);
+
+       stream_read_uint8(s, MessageId);
+
+       DEBUG_DVC("MessageId=0x%x", MessageId);
+
+       switch (MessageId)
+       {
+               case MSG_SNDIN_VERSION:
+                       error = audin_process_version(pChannelCallback, s);
+                       break;
+
+               case MSG_SNDIN_FORMATS:
+                       error = audin_process_formats(pChannelCallback, s);
+                       break;
+
+               case MSG_SNDIN_OPEN:
+                       error = audin_process_open(pChannelCallback, s);
+                       break;
+
+               case MSG_SNDIN_FORMATCHANGE:
+                       error = audin_process_format_change(pChannelCallback, s);
+                       break;
+
+               default:
+                       DEBUG_WARN("unknown MessageId=0x%x", MessageId);
+                       error = 1;
+                       break;
+       }
+
+       stream_detach(s);
+       stream_free(s);
+
+       return error;
+}
+
+static int audin_on_close(IWTSVirtualChannelCallback* pChannelCallback)
+{
+       AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
+       AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin;
+
+       DEBUG_DVC("");
+
+       if (audin->device)
+               IFCALL(audin->device->Close, audin->device);
+
+       xfree(callback->formats);
+       xfree(callback);
+
+       return 0;
+}
+
+static int audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
+       IWTSVirtualChannel* pChannel, uint8* Data, int* pbAccept,
+       IWTSVirtualChannelCallback** ppCallback)
+{
+       AUDIN_CHANNEL_CALLBACK* callback;
+       AUDIN_LISTENER_CALLBACK* listener_callback = (AUDIN_LISTENER_CALLBACK*) pListenerCallback;
+
+       DEBUG_DVC("");
+
+       callback = xnew(AUDIN_CHANNEL_CALLBACK);
+
+       callback->iface.OnDataReceived = audin_on_data_received;
+       callback->iface.OnClose = audin_on_close;
+       callback->plugin = listener_callback->plugin;
+       callback->channel_mgr = listener_callback->channel_mgr;
+       callback->channel = pChannel;
+
+       *ppCallback = (IWTSVirtualChannelCallback*) callback;
+
+       return 0;
+}
+
+static int audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
+{
+       AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
+
+       DEBUG_DVC("");
+
+       audin->listener_callback = xnew(AUDIN_LISTENER_CALLBACK);
+
+       audin->listener_callback->iface.OnNewChannelConnection = audin_on_new_channel_connection;
+       audin->listener_callback->plugin = pPlugin;
+       audin->listener_callback->channel_mgr = pChannelMgr;
+
+       return pChannelMgr->CreateListener(pChannelMgr, "AUDIO_INPUT", 0,
+               (IWTSListenerCallback*) audin->listener_callback, NULL);
+}
+
+static int audin_plugin_terminated(IWTSPlugin* pPlugin)
+{
+       AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
+
+       DEBUG_DVC("");
+
+       if (audin->device)
+       {
+               IFCALL(audin->device->Close, audin->device);
+               IFCALL(audin->device->Free, audin->device);
+               audin->device = NULL;
+       }
+
+       xfree(audin->listener_callback);
+       xfree(audin);
+
+       return 0;
+}
+
+static void audin_register_device_plugin(IWTSPlugin* pPlugin, IAudinDevice* device)
+{
+       AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
+
+       if (audin->device)
+       {
+               DEBUG_WARN("existing device, abort.");
+               return;
+       }
+
+       DEBUG_DVC("device registered.");
+
+       audin->device = device;
+}
+
+static boolean audin_load_device_plugin(IWTSPlugin* pPlugin, const char* name, RDP_PLUGIN_DATA* data)
+{
+       char* fullname;
+       PFREERDP_AUDIN_DEVICE_ENTRY entry;
+       FREERDP_AUDIN_DEVICE_ENTRY_POINTS entryPoints;
+
+       if (strrchr(name, '.') != NULL)
+       {
+               entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_plugin(name, AUDIN_DEVICE_EXPORT_FUNC_NAME);
+       }
+       else
+       {
+               fullname = xzalloc(strlen(name) + 8);
+               strcpy(fullname, "audin_");
+               strcat(fullname, name);
+               entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_plugin(fullname, AUDIN_DEVICE_EXPORT_FUNC_NAME);
+               xfree(fullname);
+       }
+
+       if (entry == NULL)
+               return false;
+
+       entryPoints.plugin = pPlugin;
+       entryPoints.pRegisterAudinDevice = audin_register_device_plugin;
+       entryPoints.plugin_data = data;
+
+       if (entry(&entryPoints) != 0)
+       {
+               DEBUG_WARN("%s entry returns error.", name);
+               return false;
+       }
+
+       return true;
+}
+
+static boolean audin_process_plugin_data(IWTSPlugin* pPlugin, RDP_PLUGIN_DATA* data)
+{
+       boolean ret;
+       AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
+       RDP_PLUGIN_DATA default_data[2] = { { 0 }, { 0 } };
+
+       if (data->data[0] && (strcmp((char*)data->data[0], "audin") == 0 || strstr((char*) data->data[0], "/audin.") != NULL))
+       {
+               if (data->data[1] && strcmp((char*)data->data[1], "format") == 0)
+               {
+                       audin->fixed_format = atoi(data->data[2]);
+                       return true;
+               }
+               else if (data->data[1] && strcmp((char*)data->data[1], "rate") == 0)
+               {
+                       audin->fixed_rate = atoi(data->data[2]);
+                       return true;
+               }
+               else if (data->data[1] && strcmp((char*)data->data[1], "channel") == 0)
+               {
+                       audin->fixed_channel = atoi(data->data[2]);
+                       return true;
+               }
+               else if (data->data[1] && ((char*)data->data[1])[0])
+               {
+                       return audin_load_device_plugin(pPlugin, (char*) data->data[1], data);
+               }
+               else
+               {
+                       default_data[0].size = sizeof(RDP_PLUGIN_DATA);
+                       default_data[0].data[0] = "audin";
+                       default_data[0].data[1] = "pulse";
+                       default_data[0].data[2] = "";
+
+                       ret = audin_load_device_plugin(pPlugin, "pulse", default_data);
+
+                       if (!ret)
+                       {
+                               default_data[0].size = sizeof(RDP_PLUGIN_DATA);
+                               default_data[0].data[0] = "audin";
+                               default_data[0].data[1] = "alsa";
+                               default_data[0].data[2] = "default";
+                               ret = audin_load_device_plugin(pPlugin, "alsa", default_data);
+                       }
+
+                       return ret;
+               }
+       }
+
+       return true;
+}
+
+int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
+{
+       int error = 0;
+       AUDIN_PLUGIN* audin;
+
+       audin = (AUDIN_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "audin");
+
+       if (audin == NULL)
+       {
+               audin = xnew(AUDIN_PLUGIN);
+
+               audin->iface.Initialize = audin_plugin_initialize;
+               audin->iface.Connected = NULL;
+               audin->iface.Disconnected = NULL;
+               audin->iface.Terminated = audin_plugin_terminated;
+               error = pEntryPoints->RegisterPlugin(pEntryPoints, "audin", (IWTSPlugin*) audin);
+       }
+
+       if (error == 0)
+               audin_process_plugin_data((IWTSPlugin*) audin, pEntryPoints->GetPluginData(pEntryPoints));
+
+       return error;
+}
+
diff --git a/channels/drdynvc/audin/audin_main.h b/channels/drdynvc/audin/audin_main.h
new file mode 100644 (file)
index 0000000..6ac45a2
--- /dev/null
@@ -0,0 +1,65 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Audio Input Redirection Virtual Channel
+ *
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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 __AUDIN_MAIN_H
+#define __AUDIN_MAIN_H
+
+#include "drdynvc_types.h"
+
+typedef boolean (*AudinReceive) (uint8* data, int size, void* user_data);
+
+typedef struct audin_format audinFormat;
+struct audin_format
+{
+       uint16 wFormatTag;
+       uint16 nChannels;
+       uint32 nSamplesPerSec;
+       uint16 nBlockAlign;
+       uint16 wBitsPerSample;
+       uint16 cbSize;
+       uint8* data;
+};
+
+typedef struct _IAudinDevice IAudinDevice;
+struct _IAudinDevice
+{
+       void (*Open) (IAudinDevice* devplugin, AudinReceive receive, void* user_data);
+       boolean (*FormatSupported) (IAudinDevice* devplugin, audinFormat* format);
+       void (*SetFormat) (IAudinDevice* devplugin, audinFormat* format, uint32 FramesPerPacket);
+       void (*Close) (IAudinDevice* devplugin);
+       void (*Free) (IAudinDevice* devplugin);
+};
+
+#define AUDIN_DEVICE_EXPORT_FUNC_NAME "FreeRDPAudinDeviceEntry"
+
+typedef void (*PREGISTERAUDINDEVICE)(IWTSPlugin* plugin, IAudinDevice* device);
+
+struct _FREERDP_AUDIN_DEVICE_ENTRY_POINTS
+{
+       IWTSPlugin* plugin;
+       PREGISTERAUDINDEVICE pRegisterAudinDevice;
+       RDP_PLUGIN_DATA* plugin_data;
+};
+typedef struct _FREERDP_AUDIN_DEVICE_ENTRY_POINTS FREERDP_AUDIN_DEVICE_ENTRY_POINTS;
+typedef FREERDP_AUDIN_DEVICE_ENTRY_POINTS* PFREERDP_AUDIN_DEVICE_ENTRY_POINTS;
+
+typedef int (*PFREERDP_AUDIN_DEVICE_ENTRY)(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints);
+
+#endif /* __AUDIN_MAIN_H */
+
diff --git a/channels/drdynvc/audin/pulse/CMakeLists.txt b/channels/drdynvc/audin/pulse/CMakeLists.txt
new file mode 100644 (file)
index 0000000..10d6afe
--- /dev/null
@@ -0,0 +1,34 @@
+# FreeRDP: A Remote Desktop Protocol Client
+# FreeRDP cmake build script
+#
+# Copyright 2011 O.S. Systems Software Ltda.
+# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
+# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set(AUDIN_PULSE_SRCS
+       audin_pulse.c
+)
+
+include_directories(..)
+include_directories(${PULSE_INCLUDE_DIRS})
+
+add_library(audin_pulse ${AUDIN_PULSE_SRCS})
+set_target_properties(audin_pulse PROPERTIES PREFIX "")
+
+target_link_libraries(audin_pulse freerdp-utils)
+target_link_libraries(audin_pulse ${PULSE_LIBRARIES})
+
+install(TARGETS audin_pulse DESTINATION ${FREERDP_PLUGIN_PATH})
+
diff --git a/channels/drdynvc/audin/pulse/audin_pulse.c b/channels/drdynvc/audin/pulse/audin_pulse.c
new file mode 100644 (file)
index 0000000..61e1427
--- /dev/null
@@ -0,0 +1,471 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Audio Input Redirection Virtual Channel - PulseAudio implementation
+ *
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pulse/pulseaudio.h>
+#include <freerdp/types.h>
+#include <freerdp/utils/memory.h>
+#include <freerdp/utils/dsp.h>
+
+#include "audin_main.h"
+
+typedef struct _AudinPulseDevice
+{
+       IAudinDevice iface;
+
+       char device_name[32];
+       uint32 frames_per_packet;
+       pa_threaded_mainloop* mainloop;
+       pa_context* context;
+       pa_sample_spec sample_spec;
+       pa_stream* stream;
+       int format;
+       int block_size;
+       ADPCM adpcm;
+
+       int bytes_per_frame;
+       uint8* buffer;
+       int buffer_frames;
+
+       AudinReceive receive;
+       void* user_data;
+} AudinPulseDevice;
+
+static void audin_pulse_context_state_callback(pa_context* context, void* userdata)
+{
+       pa_context_state_t state;
+       AudinPulseDevice* pulse = (AudinPulseDevice*) userdata;
+
+       state = pa_context_get_state(context);
+       switch (state)
+       {
+               case PA_CONTEXT_READY:
+                       DEBUG_DVC("PA_CONTEXT_READY");
+                       pa_threaded_mainloop_signal (pulse->mainloop, 0);
+                       break;
+
+               case PA_CONTEXT_FAILED:
+               case PA_CONTEXT_TERMINATED:
+                       DEBUG_DVC("state %d", (int)state);
+                       pa_threaded_mainloop_signal (pulse->mainloop, 0);
+                       break;
+
+               default:
+                       DEBUG_DVC("state %d", (int)state);
+                       break;
+       }
+}
+
+static boolean audin_pulse_connect(IAudinDevice* device)
+{
+       pa_context_state_t state;
+       AudinPulseDevice* pulse = (AudinPulseDevice*) device;
+
+       if (!pulse->context)
+               return false;
+
+       if (pa_context_connect(pulse->context, NULL, 0, NULL))
+       {
+               DEBUG_WARN("pa_context_connect failed (%d)",
+                       pa_context_errno(pulse->context));
+               return false;
+       }
+       pa_threaded_mainloop_lock(pulse->mainloop);
+       if (pa_threaded_mainloop_start(pulse->mainloop) < 0)
+       {
+               pa_threaded_mainloop_unlock(pulse->mainloop);
+               DEBUG_WARN("pa_threaded_mainloop_start failed (%d)",
+                       pa_context_errno(pulse->context));
+               return false;
+       }
+       for (;;)
+       {
+               state = pa_context_get_state(pulse->context);
+               if (state == PA_CONTEXT_READY)
+                       break;
+               if (!PA_CONTEXT_IS_GOOD(state))
+               {
+                       DEBUG_WARN("bad context state (%d)",
+                               pa_context_errno(pulse->context));
+                       break;
+               }
+               pa_threaded_mainloop_wait(pulse->mainloop);
+       }
+       pa_threaded_mainloop_unlock(pulse->mainloop);
+       if (state == PA_CONTEXT_READY)
+       {
+               DEBUG_DVC("connected");
+               return true;
+       }
+       else
+       {
+               pa_context_disconnect(pulse->context);
+               return false;
+       }
+}
+
+static void audin_pulse_free(IAudinDevice* device)
+{
+       AudinPulseDevice* pulse = (AudinPulseDevice*) device;
+
+       DEBUG_DVC("");
+
+       if (!pulse)
+               return;
+       if (pulse->mainloop)
+       {
+               pa_threaded_mainloop_stop(pulse->mainloop);
+       }
+       if (pulse->context)
+       {
+               pa_context_disconnect(pulse->context);
+               pa_context_unref(pulse->context);
+               pulse->context = NULL;
+       }
+       if (pulse->mainloop)
+       {
+               pa_threaded_mainloop_free(pulse->mainloop);
+               pulse->mainloop = NULL;
+       }
+       xfree(pulse);
+}
+
+static boolean audin_pulse_format_supported(IAudinDevice* device, audinFormat* format)
+{
+       AudinPulseDevice* pulse = (AudinPulseDevice*) device;
+
+       if (!pulse->context)
+               return 0;
+
+       switch (format->wFormatTag)
+       {
+               case 1: /* PCM */
+                       if (format->cbSize == 0 &&
+                               (format->nSamplesPerSec <= PA_RATE_MAX) &&
+                               (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) &&
+                               (format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX))
+                       {
+                               return true;
+                       }
+                       break;
+
+               case 6: /* A-LAW */
+               case 7: /* U-LAW */
+                       if (format->cbSize == 0 &&
+                               (format->nSamplesPerSec <= PA_RATE_MAX) &&
+                               (format->wBitsPerSample == 8) &&
+                               (format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX))
+                       {
+                               return true;
+                       }
+                       break;
+
+               case 0x11: /* IMA ADPCM */
+                       if ((format->nSamplesPerSec <= PA_RATE_MAX) &&
+                               (format->wBitsPerSample == 4) &&
+                               (format->nChannels == 1 || format->nChannels == 2))
+                       {
+                               return true;
+                       }
+                       break;
+       }
+       return false;
+}
+
+static void audin_pulse_set_format(IAudinDevice* device, audinFormat* format, uint32 FramesPerPacket)
+{
+       int bs;
+       pa_sample_spec sample_spec = { 0 };
+       AudinPulseDevice* pulse = (AudinPulseDevice*) device;
+
+       if (!pulse->context)
+               return;
+
+       if (FramesPerPacket > 0)
+       {
+               pulse->frames_per_packet = FramesPerPacket;
+       }
+
+       sample_spec.rate = format->nSamplesPerSec;
+       sample_spec.channels = format->nChannels;
+       switch (format->wFormatTag)
+       {
+               case 1: /* PCM */
+                       switch (format->wBitsPerSample)
+                       {
+                               case 8:
+                                       sample_spec.format = PA_SAMPLE_U8;
+                                       break;
+                               case 16:
+                                       sample_spec.format = PA_SAMPLE_S16LE;
+                                       break;
+                       }
+                       break;
+
+               case 6: /* A-LAW */
+                       sample_spec.format = PA_SAMPLE_ALAW;
+                       break;
+
+               case 7: /* 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=%d",
+                               pulse->frames_per_packet);
+                       break;
+       }
+
+       pulse->sample_spec = sample_spec;
+       pulse->format = format->wFormatTag;
+       pulse->block_size = format->nBlockAlign;
+}
+
+static void audin_pulse_stream_state_callback(pa_stream* stream, void* userdata)
+{
+       pa_stream_state_t state;
+       AudinPulseDevice* pulse = (AudinPulseDevice*) userdata;
+
+       state = pa_stream_get_state(stream);
+       switch (state)
+       {
+               case PA_STREAM_READY:
+                       DEBUG_DVC("PA_STREAM_READY");
+                       pa_threaded_mainloop_signal(pulse->mainloop, 0);
+                       break;
+
+               case PA_STREAM_FAILED:
+               case PA_STREAM_TERMINATED:
+                       DEBUG_DVC("state %d", (int)state);
+                       pa_threaded_mainloop_signal(pulse->mainloop, 0);
+                       break;
+
+               default:
+                       DEBUG_DVC("state %d", (int)state);
+                       break;
+       }
+}
+
+static void audin_pulse_stream_request_callback(pa_stream* stream, size_t length, void* userdata)
+{
+       int frames;
+       int cframes;
+       boolean ret;
+       const void* data;
+       const uint8* src;
+       int encoded_size;
+       uint8* encoded_data;
+       AudinPulseDevice* pulse = (AudinPulseDevice*) userdata;
+
+       pa_stream_peek(stream, &data, &length);
+       frames = length / pulse->bytes_per_frame;
+
+       DEBUG_DVC("length %d frames %d", (int) length, frames);
+
+       src = (const uint8*) 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)
+                       {
+                               encoded_data = dsp_encode_ima_adpcm(&pulse->adpcm,
+                                       pulse->buffer, pulse->buffer_frames * pulse->bytes_per_frame,
+                                       pulse->sample_spec.channels, pulse->block_size, &encoded_size);
+                               DEBUG_DVC("encoded %d to %d",
+                                       pulse->buffer_frames * pulse->bytes_per_frame, encoded_size);
+                       }
+                       else
+                       {
+                               encoded_data = pulse->buffer;
+                               encoded_size = pulse->buffer_frames * pulse->bytes_per_frame;
+                       }
+
+                       ret = pulse->receive(encoded_data, encoded_size, pulse->user_data);
+                       pulse->buffer_frames = 0;
+                       if (encoded_data != pulse->buffer)
+                               xfree(encoded_data);
+                       if (!ret)
+                               break;
+               }
+               src += cframes * pulse->bytes_per_frame;
+               frames -= cframes;
+       }
+
+       pa_stream_drop(stream);
+}
+
+
+static void audin_pulse_close(IAudinDevice* device)
+{
+       AudinPulseDevice* pulse = (AudinPulseDevice*) device;
+
+       if (!pulse->context || !pulse->stream)
+               return;
+
+       DEBUG_DVC("");
+
+       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);
+
+       pulse->receive = NULL;
+       pulse->user_data = NULL;
+       if (pulse->buffer)
+       {
+               xfree(pulse->buffer);
+               pulse->buffer = NULL;
+               pulse->buffer_frames = 0;
+       }
+}
+
+static void audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* user_data)
+{
+       pa_stream_state_t state;
+       pa_buffer_attr buffer_attr = { 0 };
+       AudinPulseDevice* pulse = (AudinPulseDevice*) device;
+
+       if (!pulse->context)
+               return;
+       if (!pulse->sample_spec.rate || pulse->stream)
+               return;
+
+       DEBUG_DVC("");
+
+       pulse->receive = receive;
+       pulse->user_data = user_data;
+
+       pa_threaded_mainloop_lock(pulse->mainloop);
+       pulse->stream = pa_stream_new(pulse->context, "freerdp_audin",
+               &pulse->sample_spec, NULL);
+       if (!pulse->stream)
+       {
+               pa_threaded_mainloop_unlock(pulse->mainloop);
+               DEBUG_DVC("pa_stream_new failed (%d)",
+                       pa_context_errno(pulse->context));
+               return;
+       }
+       pulse->bytes_per_frame = pa_frame_size(&pulse->sample_spec);
+       pa_stream_set_state_callback(pulse->stream,
+               audin_pulse_stream_state_callback, pulse);
+       pa_stream_set_read_callback(pulse->stream,
+               audin_pulse_stream_request_callback, pulse);
+       buffer_attr.maxlength = (uint32_t) -1;
+       buffer_attr.tlength = (uint32_t) -1;
+       buffer_attr.prebuf = (uint32_t) -1;
+       buffer_attr.minreq = (uint32_t) -1;
+       /* 500ms latency */
+       buffer_attr.fragsize = pa_usec_to_bytes(500000, &pulse->sample_spec);
+       if (pa_stream_connect_record(pulse->stream,
+               pulse->device_name[0] ? pulse->device_name : NULL,
+               &buffer_attr, PA_STREAM_ADJUST_LATENCY) < 0)
+       {
+               pa_threaded_mainloop_unlock(pulse->mainloop);
+               DEBUG_WARN("pa_stream_connect_playback failed (%d)",
+                       pa_context_errno(pulse->context));
+               return;
+       }
+
+       for (;;)
+       {
+               state = pa_stream_get_state(pulse->stream);
+               if (state == PA_STREAM_READY)
+                       break;
+               if (!PA_STREAM_IS_GOOD(state))
+               {
+                       DEBUG_WARN("bad stream state (%d)",
+                               pa_context_errno(pulse->context));
+                       break;
+               }
+               pa_threaded_mainloop_wait(pulse->mainloop);
+       }
+       pa_threaded_mainloop_unlock(pulse->mainloop);
+       if (state == PA_STREAM_READY)
+       {
+               memset(&pulse->adpcm, 0, sizeof(ADPCM));
+               pulse->buffer = xzalloc(pulse->bytes_per_frame * pulse->frames_per_packet);
+               pulse->buffer_frames = 0;
+               DEBUG_DVC("connected");
+       }
+       else
+       {
+               audin_pulse_close(device);
+       }
+}
+
+int FreeRDPAudinDeviceEntry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
+{
+       AudinPulseDevice* pulse;
+       RDP_PLUGIN_DATA * data;
+
+       pulse = xnew(AudinPulseDevice);
+
+       pulse->iface.Open = audin_pulse_open;
+       pulse->iface.FormatSupported = audin_pulse_format_supported;
+       pulse->iface.SetFormat = audin_pulse_set_format;
+       pulse->iface.Close = audin_pulse_close;
+       pulse->iface.Free = audin_pulse_free;
+
+       data = pEntryPoints->plugin_data;
+       if (data && data->data[0] && strcmp(data->data[0], "audin") == 0 &&
+               data->data[1] && strcmp(data->data[1], "pulse") == 0)
+       {
+               strncpy(pulse->device_name, (char*)data->data[2], sizeof(pulse->device_name));
+       }
+
+       pulse->mainloop = pa_threaded_mainloop_new();
+       if (!pulse->mainloop)
+       {
+               DEBUG_WARN("pa_threaded_mainloop_new failed");
+               audin_pulse_free((IAudinDevice*) pulse);
+               return 1;
+       }
+       pulse->context = pa_context_new(pa_threaded_mainloop_get_api(pulse->mainloop), "freerdp");
+       if (!pulse->context)
+       {
+               DEBUG_WARN("pa_context_new failed");
+               audin_pulse_free((IAudinDevice*) pulse);
+               return 1;
+       }
+       pa_context_set_state_callback(pulse->context, audin_pulse_context_state_callback, pulse);
+       if (!audin_pulse_connect((IAudinDevice*) pulse))
+       {
+               audin_pulse_free((IAudinDevice*) pulse);
+               return 1;
+       }
+
+       pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) pulse);
+
+       return 0;
+}
+
diff --git a/channels/drdynvc/drdynvc_main.c b/channels/drdynvc/drdynvc_main.c
new file mode 100644 (file)
index 0000000..27ad531
--- /dev/null
@@ -0,0 +1,346 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Dynamic Virtual Channel
+ *
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <freerdp/constants.h>
+#include <freerdp/utils/memory.h>
+#include <freerdp/utils/stream.h>
+#include <freerdp/utils/svc_plugin.h>
+#include <freerdp/utils/wait_obj.h>
+
+#include "dvcman.h"
+#include "drdynvc_types.h"
+#include "drdynvc_main.h"
+
+#define CREATE_REQUEST_PDU     0x01
+#define DATA_FIRST_PDU         0x02
+#define DATA_PDU               0x03
+#define CLOSE_REQUEST_PDU      0x04
+#define CAPABILITY_REQUEST_PDU 0x05
+
+struct drdynvc_plugin
+{
+       rdpSvcPlugin plugin;
+
+       int version;
+       int PriorityCharge0;
+       int PriorityCharge1;
+       int PriorityCharge2;
+       int PriorityCharge3;
+
+       IWTSVirtualChannelManager* channel_mgr;
+};
+
+static int drdynvc_write_variable_uint(STREAM* stream, uint32 val)
+{
+       int cb;
+
+       if (val <= 0xFF)
+       {
+               cb = 0;
+               stream_write_uint8(stream, val);
+       }
+       else if (val <= 0xFFFF)
+       {
+               cb = 1;
+               stream_write_uint16(stream, val);
+       }
+       else
+       {
+               cb = 3;
+               stream_write_uint32(stream, val);
+       }
+       return cb;
+}
+
+int drdynvc_write_data(drdynvcPlugin* drdynvc, uint32 ChannelId, uint8* data, uint32 data_size)
+{
+       STREAM* data_out;
+       uint32 pos = 0;
+       uint32 cbChId;
+       uint32 cbLen;
+       uint32 chunk_len;
+       int error;
+
+       DEBUG_DVC("ChannelId=%d size=%d", ChannelId, data_size);
+
+       data_out = stream_new(CHANNEL_CHUNK_LENGTH);
+       stream_set_pos(data_out, 1);
+       cbChId = drdynvc_write_variable_uint(data_out, ChannelId);
+
+       if (data_size <= CHANNEL_CHUNK_LENGTH - pos)
+       {
+               pos = stream_get_pos(data_out);
+               stream_set_pos(data_out, 0);
+               stream_write_uint8(data_out, 0x30 | cbChId);
+               stream_set_pos(data_out, pos);
+               stream_write(data_out, data, data_size);
+               error = svc_plugin_send((rdpSvcPlugin*)drdynvc, data_out);
+       }
+       else
+       {
+               /* Fragment the data */
+               cbLen = drdynvc_write_variable_uint(data_out, data_size);
+               pos = stream_get_pos(data_out);
+               stream_set_pos(data_out, 0);
+               stream_write_uint8(data_out, 0x20 | cbChId | (cbLen << 2));
+               stream_set_pos(data_out, pos);
+               chunk_len = CHANNEL_CHUNK_LENGTH - pos;
+               stream_write(data_out, data, chunk_len);
+               data += chunk_len;
+               data_size -= chunk_len;
+               error = svc_plugin_send((rdpSvcPlugin*)drdynvc, data_out);
+
+               while (error == CHANNEL_RC_OK && data_size > 0)
+               {
+                       data_out = stream_new(CHANNEL_CHUNK_LENGTH);
+                       stream_set_pos(data_out, 1);
+                       cbChId = drdynvc_write_variable_uint(data_out, ChannelId);
+
+                       pos = stream_get_pos(data_out);
+                       stream_set_pos(data_out, 0);
+                       stream_write_uint8(data_out, 0x30 | cbChId);
+                       stream_set_pos(data_out, pos);
+
+                       chunk_len = data_size;
+                       if (chunk_len > CHANNEL_CHUNK_LENGTH - pos)
+                               chunk_len = CHANNEL_CHUNK_LENGTH - pos;
+                       stream_write(data_out, data, chunk_len);
+                       data += chunk_len;
+                       data_size -= chunk_len;
+                       error = svc_plugin_send((rdpSvcPlugin*)drdynvc, data_out);
+               }
+       }
+       if (error != CHANNEL_RC_OK)
+       {
+               DEBUG_WARN("VirtualChannelWrite failed %d", error);
+               return 1;
+       }
+       return 0;
+}
+
+int drdynvc_push_event(drdynvcPlugin* drdynvc, RDP_EVENT* event)
+{
+       int error;
+
+       error = svc_plugin_send_event((rdpSvcPlugin*)drdynvc, event);
+       if (error != CHANNEL_RC_OK)
+       {
+               DEBUG_WARN("pVirtualChannelEventPush failed %d", error);
+               return 1;
+       }
+       return 0;
+}
+
+static int drdynvc_process_capability_request(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* s)
+{
+       STREAM* data_out;
+       int error;
+
+       DEBUG_DVC("Sp=%d cbChId=%d", Sp, cbChId);
+       stream_seek(s, 1); /* pad */
+       stream_read_uint16(s, drdynvc->version);
+       if (drdynvc->version == 2)
+       {
+               stream_read_uint16(s, drdynvc->PriorityCharge0);
+               stream_read_uint16(s, drdynvc->PriorityCharge1);
+               stream_read_uint16(s, drdynvc->PriorityCharge2);
+               stream_read_uint16(s, drdynvc->PriorityCharge3);
+       }
+       data_out = stream_new(4);
+       stream_write_uint16(data_out, 0x0050); /* Cmd+Sp+cbChId+Pad. Note: MSTSC sends 0x005c */
+       stream_write_uint16(data_out, drdynvc->version);
+       error = svc_plugin_send((rdpSvcPlugin*)drdynvc, data_out);
+       if (error != CHANNEL_RC_OK)
+       {
+               DEBUG_WARN("VirtualChannelWrite failed %d", error);
+               return 1;
+       }
+       return 0;
+}
+
+static uint32 drdynvc_read_variable_uint(STREAM* stream, int cbLen)
+{
+       uint32 val;
+
+       switch (cbLen)
+       {
+               case 0:
+                       stream_read_uint8(stream, val);
+                       break;
+               case 1:
+                       stream_read_uint16(stream, val);
+                       break;
+               default:
+                       stream_read_uint32(stream, val);
+                       break;
+       }
+       return val;
+}
+
+static int drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* s)
+{
+       STREAM* data_out;
+       int pos;
+       int error;
+       uint32 ChannelId;
+
+       ChannelId = drdynvc_read_variable_uint(s, cbChId);
+       pos = stream_get_pos(s);
+       DEBUG_DVC("ChannelId=%d ChannelName=%s", ChannelId, stream_get_tail(s));
+
+       error = dvcman_create_channel(drdynvc->channel_mgr, ChannelId, (char*)stream_get_tail(s));
+
+       data_out = stream_new(pos + 4);
+       stream_write_uint8(data_out, 0x10 | cbChId);
+       stream_set_pos(s, 1);
+       stream_copy(data_out, s, pos - 1);
+       
+       if (error == 0)
+       {
+               DEBUG_DVC("channel created");
+               stream_write_uint32(data_out, 0);
+       }
+       else
+       {
+               DEBUG_DVC("no listener");
+               stream_write_uint32(data_out, (uint32)(-1));
+       }
+
+       error = svc_plugin_send((rdpSvcPlugin*)drdynvc, data_out);
+       if (error != CHANNEL_RC_OK)
+       {
+               DEBUG_WARN("VirtualChannelWrite failed %d", error);
+               return 1;
+       }
+       return 0;
+}
+
+static int drdynvc_process_data_first(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* s)
+{
+       uint32 ChannelId;
+       uint32 Length;
+       int error;
+
+       ChannelId = drdynvc_read_variable_uint(s, cbChId);
+       Length = drdynvc_read_variable_uint(s, Sp);
+       DEBUG_DVC("ChannelId=%d Length=%d", ChannelId, Length);
+
+       error = dvcman_receive_channel_data_first(drdynvc->channel_mgr, ChannelId, Length);
+       if (error)
+               return error;
+
+       return dvcman_receive_channel_data(drdynvc->channel_mgr, ChannelId,
+               stream_get_tail(s), stream_get_left(s));
+}
+
+static int drdynvc_process_data(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* s)
+{
+       uint32 ChannelId;
+
+       ChannelId = drdynvc_read_variable_uint(s, cbChId);
+       DEBUG_DVC("ChannelId=%d", ChannelId);
+
+       return dvcman_receive_channel_data(drdynvc->channel_mgr, ChannelId,
+               stream_get_tail(s), stream_get_left(s));
+}
+
+static int drdynvc_process_close_request(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* s)
+{
+       uint32 ChannelId;
+
+       ChannelId = drdynvc_read_variable_uint(s, cbChId);
+       DEBUG_DVC("ChannelId=%d", ChannelId);
+       dvcman_close_channel(drdynvc->channel_mgr, ChannelId);
+
+       return 0;
+}
+
+static void drdynvc_process_receive(rdpSvcPlugin* plugin, STREAM* s)
+{
+       drdynvcPlugin* drdynvc = (drdynvcPlugin*)plugin;
+       int value;
+       int Cmd;
+       int Sp;
+       int cbChId;
+
+       stream_read_uint8(s, value);
+       Cmd = (value & 0xf0) >> 4;
+       Sp = (value & 0x0c) >> 2;
+       cbChId = (value & 0x03) >> 0;
+
+       DEBUG_DVC("Cmd=0x%x", Cmd);
+
+       switch (Cmd)
+       {
+               case CAPABILITY_REQUEST_PDU:
+                       drdynvc_process_capability_request(drdynvc, Sp, cbChId, s);
+                       break;
+               case CREATE_REQUEST_PDU:
+                       drdynvc_process_create_request(drdynvc, Sp, cbChId, s);
+                       break;
+               case DATA_FIRST_PDU:
+                       drdynvc_process_data_first(drdynvc, Sp, cbChId, s);
+                       break;
+               case DATA_PDU:
+                       drdynvc_process_data(drdynvc, Sp, cbChId, s);
+                       break;
+               case CLOSE_REQUEST_PDU:
+                       drdynvc_process_close_request(drdynvc, Sp, cbChId, s);
+                       break;
+               default:
+                       DEBUG_WARN("unknown drdynvc cmd 0x%x", Cmd);
+                       break;
+       }
+
+       stream_free(s);
+}
+
+static void drdynvc_process_connect(rdpSvcPlugin* plugin)
+{
+       drdynvcPlugin* drdynvc = (drdynvcPlugin*)plugin;
+
+       DEBUG_DVC("connecting");
+
+       drdynvc->channel_mgr = dvcman_new(drdynvc);
+       dvcman_load_plugin(drdynvc->channel_mgr, svc_plugin_get_data(plugin));
+       dvcman_init(drdynvc->channel_mgr);
+}
+
+static void drdynvc_process_event(rdpSvcPlugin* plugin, RDP_EVENT* event)
+{
+       freerdp_event_free(event);
+}
+
+static void drdynvc_process_terminate(rdpSvcPlugin* plugin)
+{
+       drdynvcPlugin* drdynvc = (drdynvcPlugin*)plugin;
+
+       DEBUG_DVC("terminating");
+
+       if (drdynvc->channel_mgr != NULL)
+               dvcman_free(drdynvc->channel_mgr);
+       xfree(drdynvc);
+}
+
+DEFINE_SVC_PLUGIN(drdynvc, "drdynvc",
+       CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
+       CHANNEL_OPTION_COMPRESS_RDP)
diff --git a/channels/drdynvc/drdynvc_main.h b/channels/drdynvc/drdynvc_main.h
new file mode 100644 (file)
index 0000000..519c61d
--- /dev/null
@@ -0,0 +1,30 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Dynamic Virtual Channel
+ *
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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 __DRDYNVC_MAIN_H
+#define __DRDYNVC_MAIN_H
+
+#include <freerdp/types.h>
+
+typedef struct drdynvc_plugin drdynvcPlugin;
+
+int drdynvc_write_data(drdynvcPlugin* plugin, uint32 ChannelId, uint8* data, uint32 data_size);
+int drdynvc_push_event(drdynvcPlugin* plugin, RDP_EVENT* event);
+
+#endif
diff --git a/channels/drdynvc/drdynvc_types.h b/channels/drdynvc/drdynvc_types.h
new file mode 100644 (file)
index 0000000..a08a605
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Dynamic Virtual Channel
+ *
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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 __DRDYNVC_TYPES_H
+#define __DRDYNVC_TYPES_H
+
+#include "config.h"
+#include <freerdp/dvc.h>
+#include <freerdp/types.h>
+#include <freerdp/utils/debug.h>
+
+#ifdef WITH_DEBUG_DVC
+#define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
+#endif
+
+#endif
diff --git a/channels/drdynvc/dvcman.c b/channels/drdynvc/dvcman.c
new file mode 100644 (file)
index 0000000..d24b114
--- /dev/null
@@ -0,0 +1,441 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Dynamic Virtual Channel Manager
+ *
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <freerdp/utils/memory.h>
+#include <freerdp/utils/stream.h>
+#include <freerdp/utils/list.h>
+#include <freerdp/utils/load_plugin.h>
+
+#include "drdynvc_types.h"
+#include "dvcman.h"
+
+#define MAX_PLUGINS 10
+
+typedef struct _DVCMAN DVCMAN;
+struct _DVCMAN
+{
+       IWTSVirtualChannelManager iface;
+
+       drdynvcPlugin* drdynvc;
+
+       const char* plugin_names[MAX_PLUGINS];
+       IWTSPlugin* plugins[MAX_PLUGINS];
+       int num_plugins;
+
+       IWTSListener* listeners[MAX_PLUGINS];
+       int num_listeners;
+
+       LIST* channels;
+};
+
+typedef struct _DVCMAN_LISTENER DVCMAN_LISTENER;
+struct _DVCMAN_LISTENER
+{
+       IWTSListener iface;
+
+       DVCMAN* dvcman;
+       char* channel_name;
+       uint32 flags;
+       IWTSListenerCallback* listener_callback;
+};
+
+typedef struct _DVCMAN_ENTRY_POINTS DVCMAN_ENTRY_POINTS;
+struct _DVCMAN_ENTRY_POINTS
+{
+       IDRDYNVC_ENTRY_POINTS iface;
+
+       DVCMAN* dvcman;
+       RDP_PLUGIN_DATA* plugin_data;
+};
+
+typedef struct _DVCMAN_CHANNEL DVCMAN_CHANNEL;
+struct _DVCMAN_CHANNEL
+{
+       IWTSVirtualChannel iface;
+
+       DVCMAN* dvcman;
+       DVCMAN_CHANNEL* next;
+       uint32 channel_id;
+       IWTSVirtualChannelCallback* channel_callback;
+
+       STREAM* dvc_data;
+};
+
+static int dvcman_get_configuration(IWTSListener* pListener, void** ppPropertyBag)
+{
+       *ppPropertyBag = NULL;
+       return 1;
+}
+
+static int dvcman_create_listener(IWTSVirtualChannelManager* pChannelMgr,
+       const char* pszChannelName, uint32 ulFlags,
+       IWTSListenerCallback* pListenerCallback, IWTSListener** ppListener)
+{
+       DVCMAN* dvcman = (DVCMAN*)pChannelMgr;
+       DVCMAN_LISTENER* listener;
+
+       if (dvcman->num_listeners < MAX_PLUGINS)
+       {
+               DEBUG_DVC("%d.%s.", dvcman->num_listeners, pszChannelName);
+               listener = xnew(DVCMAN_LISTENER);
+               listener->iface.GetConfiguration = dvcman_get_configuration;
+               listener->dvcman = dvcman;
+               listener->channel_name = xstrdup(pszChannelName);
+               listener->flags = ulFlags;
+               listener->listener_callback = pListenerCallback;
+
+               if (ppListener)
+                       *ppListener = (IWTSListener*)listener;
+               dvcman->listeners[dvcman->num_listeners++] = (IWTSListener*)listener;
+               return 0;
+       }
+       else
+       {
+               DEBUG_WARN("Maximum DVC listener number reached.");
+               return 1;
+       }
+}
+
+static int dvcman_push_event(IWTSVirtualChannelManager* pChannelMgr, RDP_EVENT* pEvent)
+{
+       int error;
+       DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
+
+       error = drdynvc_push_event(dvcman->drdynvc, pEvent);
+
+       if (error == 0)
+       {
+               DEBUG_DVC("event_type %d pushed.", pEvent->event_type);
+       }
+       else
+       {
+               DEBUG_WARN("event_type %d push failed.", pEvent->event_type);
+       }
+
+       return error;
+}
+
+static int dvcman_register_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const char* name, IWTSPlugin* pPlugin)
+{
+       DVCMAN* dvcman = ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->dvcman;
+
+       if (dvcman->num_plugins < MAX_PLUGINS)
+       {
+               DEBUG_DVC("num_plugins %d", dvcman->num_plugins);
+               dvcman->plugin_names[dvcman->num_plugins] = name;
+               dvcman->plugins[dvcman->num_plugins++] = pPlugin;
+               return 0;
+       }
+       else
+       {
+               DEBUG_WARN("Maximum DVC plugin number reached.");
+               return 1;
+       }
+}
+
+IWTSPlugin* dvcman_get_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const char* name)
+{
+       int i;
+       DVCMAN* dvcman = ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->dvcman;
+
+       for (i = 0; i < dvcman->num_plugins; i++)
+       {
+               if (dvcman->plugin_names[i] == name ||
+                       strcmp(dvcman->plugin_names[i], name) == 0)
+               {
+                       return dvcman->plugins[i];
+               }
+       }
+
+       return NULL;
+}
+
+RDP_PLUGIN_DATA* dvcman_get_plugin_data(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
+{
+       return ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->plugin_data;
+}
+
+IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin)
+{
+       DVCMAN* dvcman;
+
+       dvcman = xnew(DVCMAN);
+       dvcman->iface.CreateListener = dvcman_create_listener;
+       dvcman->iface.PushEvent = dvcman_push_event;
+       dvcman->drdynvc = plugin;
+       dvcman->channels = list_new();
+
+       return (IWTSVirtualChannelManager*) dvcman;
+}
+
+int dvcman_load_plugin(IWTSVirtualChannelManager* pChannelMgr, RDP_PLUGIN_DATA* data)
+{
+       DVCMAN_ENTRY_POINTS entryPoints;
+       PDVC_PLUGIN_ENTRY pDVCPluginEntry = NULL;
+
+       while (data && data->size > 0)
+       {
+               pDVCPluginEntry = freerdp_load_plugin((char*) data->data[0], "DVCPluginEntry");
+
+               if (pDVCPluginEntry != NULL)
+               {
+                       entryPoints.iface.RegisterPlugin = dvcman_register_plugin;
+                       entryPoints.iface.GetPlugin = dvcman_get_plugin;
+                       entryPoints.iface.GetPluginData = dvcman_get_plugin_data;
+                       entryPoints.dvcman = (DVCMAN*) pChannelMgr;
+                       entryPoints.plugin_data = data;
+                       pDVCPluginEntry((IDRDYNVC_ENTRY_POINTS*) &entryPoints);
+               }
+               
+               data = (RDP_PLUGIN_DATA*)(((void*) data) + data->size);
+       }
+
+       return 0;
+}
+
+static void dvcman_channel_free(DVCMAN_CHANNEL* channel)
+{
+       if (channel->channel_callback)
+               channel->channel_callback->OnClose(channel->channel_callback);
+
+       xfree(channel);
+}
+
+void dvcman_free(IWTSVirtualChannelManager* pChannelMgr)
+{
+       int i;
+       IWTSPlugin* pPlugin;
+       DVCMAN_LISTENER* listener;
+       DVCMAN_CHANNEL* channel;
+       DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
+
+       while ((channel = (DVCMAN_CHANNEL*) list_dequeue(dvcman->channels)) != NULL)
+               dvcman_channel_free(channel);
+
+       list_free(dvcman->channels);
+
+       for (i = 0; i < dvcman->num_listeners; i++)
+       {
+               listener = (DVCMAN_LISTENER*) dvcman->listeners[i];
+               xfree(listener->channel_name);
+               xfree(listener);
+       }
+
+       for (i = 0; i < dvcman->num_plugins; i++)
+       {
+               pPlugin = dvcman->plugins[i];
+
+               if (pPlugin->Terminated)
+                       pPlugin->Terminated(pPlugin);
+       }
+
+       xfree(dvcman);
+}
+
+int dvcman_init(IWTSVirtualChannelManager* pChannelMgr)
+{
+       int i;
+       IWTSPlugin* pPlugin;
+       DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
+
+       for (i = 0; i < dvcman->num_plugins; i++)
+       {
+               pPlugin = dvcman->plugins[i];
+
+               if (pPlugin->Initialize)
+                       pPlugin->Initialize(pPlugin, pChannelMgr);
+       }
+
+       return 0;
+}
+
+static int dvcman_write_channel(IWTSVirtualChannel* pChannel, uint32 cbSize, uint8* pBuffer, void* pReserved)
+{
+       DVCMAN_CHANNEL* channel = (DVCMAN_CHANNEL*) pChannel;
+
+       return drdynvc_write_data(channel->dvcman->drdynvc, channel->channel_id, pBuffer, cbSize);
+}
+
+static int dvcman_close_channel_iface(IWTSVirtualChannel* pChannel)
+{
+       DVCMAN_CHANNEL* channel = (DVCMAN_CHANNEL*) pChannel;
+       DVCMAN* dvcman = channel->dvcman;
+
+       DEBUG_DVC("id=%d", channel->channel_id);
+
+       if (list_remove(dvcman->channels, channel) == NULL)
+               DEBUG_WARN("channel not found");
+
+       dvcman_channel_free(channel);
+
+       return 1;
+}
+
+int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId, const char* ChannelName)
+{
+       int i;
+       int bAccept;
+       DVCMAN_LISTENER* listener;
+       DVCMAN_CHANNEL* channel;
+       IWTSVirtualChannelCallback* pCallback;
+       DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
+
+       for (i = 0; i < dvcman->num_listeners; i++)
+       {
+               listener = (DVCMAN_LISTENER*)dvcman->listeners[i];
+
+               if (strcmp(listener->channel_name, ChannelName) == 0)
+               {
+                       channel = xnew(DVCMAN_CHANNEL);
+                       channel->iface.Write = dvcman_write_channel;
+                       channel->iface.Close = dvcman_close_channel_iface;
+                       channel->dvcman = dvcman;
+                       channel->channel_id = ChannelId;
+
+                       bAccept = 1;
+                       pCallback = NULL;
+
+                       if (listener->listener_callback->OnNewChannelConnection(listener->listener_callback,
+                               (IWTSVirtualChannel*) channel, NULL, &bAccept, &pCallback) == 0 && bAccept == 1)
+                       {
+                               DEBUG_DVC("listener %s created new channel %d",
+                                         listener->channel_name, channel->channel_id);
+                               channel->channel_callback = pCallback;
+                               list_add(dvcman->channels, channel);
+
+                               return 0;
+                       }
+                       else
+                       {
+                               DEBUG_WARN("channel rejected by plugin");
+                               dvcman_channel_free(channel);
+                               return 1;
+                       }
+               }
+       }
+
+       return 1;
+}
+
+static DVCMAN_CHANNEL* dvcman_find_channel_by_id(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId)
+{
+       LIST_ITEM* curr;
+       DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
+
+       for (curr = dvcman->channels->head; curr; curr = curr->next)
+       {
+               if (((DVCMAN_CHANNEL*) curr->data)->channel_id == ChannelId)
+               {
+                       return (DVCMAN_CHANNEL*)curr->data;
+               }
+       }
+
+       return NULL;
+}
+
+int dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId)
+{
+       DVCMAN_CHANNEL* channel;
+       IWTSVirtualChannel* ichannel;
+
+       channel = dvcman_find_channel_by_id(pChannelMgr, ChannelId);
+
+       if (channel == NULL)
+       {
+               DEBUG_WARN("ChannelId %d not found!", ChannelId);
+               return 1;
+       }
+
+       if (channel->dvc_data)
+       {
+               stream_free(channel->dvc_data);
+               channel->dvc_data = NULL;
+       }
+
+       DEBUG_DVC("dvcman_close_channel: channel %d closed", ChannelId);
+       ichannel = (IWTSVirtualChannel*)channel;
+       ichannel->Close(ichannel);
+
+       return 0;
+}
+
+int dvcman_receive_channel_data_first(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId, uint32 length)
+{
+       DVCMAN_CHANNEL* channel;
+
+       channel = dvcman_find_channel_by_id(pChannelMgr, ChannelId);
+
+       if (channel == NULL)
+       {
+               DEBUG_WARN("ChannelId %d not found!", ChannelId);
+               return 1;
+       }
+
+       if (channel->dvc_data)
+               stream_free(channel->dvc_data);
+
+       channel->dvc_data = stream_new(length);
+
+       return 0;
+}
+
+int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId, uint8* data, uint32 data_size)
+{
+       int error = 0;
+       DVCMAN_CHANNEL* channel;
+
+       channel = dvcman_find_channel_by_id(pChannelMgr, ChannelId);
+
+       if (channel == NULL)
+       {
+               DEBUG_WARN("ChannelId %d not found!", ChannelId);
+               return 1;
+       }
+
+       if (channel->dvc_data)
+       {
+               /* Fragmented data */
+               if (stream_get_length(channel->dvc_data) + data_size > stream_get_size(channel->dvc_data))
+               {
+                       DEBUG_WARN("data exceeding declared length!");
+                       stream_free(channel->dvc_data);
+                       channel->dvc_data = NULL;
+                       return 1;
+               }
+
+               stream_write(channel->dvc_data, data, data_size);
+
+               if (stream_get_length(channel->dvc_data) >= stream_get_size(channel->dvc_data))
+               {
+                       error = channel->channel_callback->OnDataReceived(channel->channel_callback,
+                               stream_get_size(channel->dvc_data), stream_get_data(channel->dvc_data));
+                       stream_free(channel->dvc_data);
+                       channel->dvc_data = NULL;
+               }
+       }
+       else
+       {
+               error = channel->channel_callback->OnDataReceived(channel->channel_callback, data_size, data);
+       }
+
+       return error;
+}
diff --git a/channels/drdynvc/dvcman.h b/channels/drdynvc/dvcman.h
new file mode 100644 (file)
index 0000000..679243f
--- /dev/null
@@ -0,0 +1,35 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Dynamic Virtual Channel Manager
+ *
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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 __DVCMAN_H
+#define __DVCMAN_H
+
+#include <freerdp/dvc.h>
+#include "drdynvc_main.h"
+
+IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin);
+int dvcman_load_plugin(IWTSVirtualChannelManager* pChannelMgr, RDP_PLUGIN_DATA* data);
+void dvcman_free(IWTSVirtualChannelManager* pChannelMgr);
+int dvcman_init(IWTSVirtualChannelManager* pChannelMgr);
+int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId, const char* ChannelName);
+int dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId);
+int dvcman_receive_channel_data_first(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId, uint32 length);
+int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId, uint8* data, uint32 data_size);
+
+#endif
diff --git a/channels/drdynvc/tsmf/CMakeLists.txt b/channels/drdynvc/tsmf/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e28cac6
--- /dev/null
@@ -0,0 +1,57 @@
+# FreeRDP: A Remote Desktop Protocol Client
+# FreeRDP cmake build script
+#
+# Copyright 2011 O.S. Systems Software Ltda.
+# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
+# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set(TSMF_SRCS
+       tsmf_audio.c
+       tsmf_audio.h
+       tsmf_codec.c
+       tsmf_codec.h
+       tsmf_constants.h
+       tsmf_decoder.c
+       tsmf_decoder.h
+       tsmf_ifman.c
+       tsmf_ifman.h
+       tsmf_main.c
+       tsmf_main.h
+       tsmf_media.c
+       tsmf_media.h
+       tsmf_types.h
+)
+
+include_directories(..)
+
+add_library(tsmf ${TSMF_SRCS})
+set_target_properties(tsmf PROPERTIES PREFIX "")
+
+target_link_libraries(tsmf freerdp-utils)
+
+install(TARGETS tsmf DESTINATION ${FREERDP_PLUGIN_PATH})
+
+if(WITH_FFMPEG)
+       add_subdirectory(ffmpeg)
+endif()
+
+if(WITH_ALSA)
+       add_subdirectory(alsa)
+endif()
+
+if(WITH_PULSEAUDIO)
+       add_subdirectory(pulse)
+endif()
+
diff --git a/channels/drdynvc/tsmf/alsa/CMakeLists.txt b/channels/drdynvc/tsmf/alsa/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c769a18
--- /dev/null
@@ -0,0 +1,34 @@
+# FreeRDP: A Remote Desktop Protocol Client
+# FreeRDP cmake build script
+#
+# Copyright 2011 O.S. Systems Software Ltda.
+# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
+# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set(TSMF_ALSA_SRCS
+       tsmf_alsa.c
+)
+
+include_directories(..)
+include_directories(${ALSA_INCLUDE_DIRS})
+
+add_library(tsmf_alsa ${TSMF_ALSA_SRCS})
+set_target_properties(tsmf_alsa PROPERTIES PREFIX "")
+
+target_link_libraries(tsmf_alsa freerdp-utils)
+target_link_libraries(tsmf_alsa ${ALSA_LIBRARIES})
+
+install(TARGETS tsmf_alsa DESTINATION ${FREERDP_PLUGIN_PATH})
+
diff --git a/channels/drdynvc/tsmf/alsa/tsmf_alsa.c b/channels/drdynvc/tsmf/alsa/tsmf_alsa.c
new file mode 100644 (file)
index 0000000..3017dac
--- /dev/null
@@ -0,0 +1,263 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Video Redirection Virtual Channel - ALSA Audio Device
+ *
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <alsa/asoundlib.h>
+#include <freerdp/types.h>
+#include <freerdp/utils/memory.h>
+#include <freerdp/utils/dsp.h>
+
+#include "tsmf_audio.h"
+
+typedef struct _TSMFALSAAudioDevice
+{
+       ITSMFAudioDevice iface;
+
+       char device[32];
+       snd_pcm_t* out_handle;
+       uint32 source_rate;
+       uint32 actual_rate;
+       uint32 source_channels;
+       uint32 actual_channels;
+       uint32 bytes_per_sample;
+} TSMFALSAAudioDevice;
+
+static boolean 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)
+       {
+               DEBUG_WARN("failed to open device %s", alsa->device);
+               return false;
+       }
+
+       DEBUG_DVC("open device %s", alsa->device);
+       return true;
+}
+
+static boolean tsmf_alsa_open(ITSMFAudioDevice* audio, const char* device)
+{
+       TSMFALSAAudioDevice* alsa = (TSMFALSAAudioDevice*) audio;
+
+       if (!device)
+       {
+               if (!alsa->device[0])
+                       strcpy(alsa->device, "default");
+       }
+       else
+       {
+               strcpy(alsa->device, device);
+       }
+
+       return tsmf_alsa_open_device(alsa);
+}
+
+static boolean 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)
+               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)
+       {
+               DEBUG_WARN("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_hw_params_set_format(alsa->out_handle, hw_params,
+               SND_PCM_FORMAT_S16_LE);
+       snd_pcm_hw_params_set_rate_near(alsa->out_handle, hw_params,
+               &alsa->actual_rate, NULL);
+       snd_pcm_hw_params_set_channels_near(alsa->out_handle, hw_params,
+               &alsa->actual_channels);
+       frames = sample_rate;
+       snd_pcm_hw_params_set_buffer_size_near(alsa->out_handle, hw_params,
+               &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)
+       {
+               DEBUG_WARN("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);
+       snd_pcm_sw_params(alsa->out_handle, sw_params);
+       snd_pcm_sw_params_free(sw_params);
+
+       snd_pcm_prepare(alsa->out_handle);
+
+       DEBUG_DVC("sample_rate %d channels %d bits_per_sample %d",
+               sample_rate, channels, bits_per_sample);
+       DEBUG_DVC("hardware buffer %d frames", (int)frames);
+       if ((alsa->actual_rate != alsa->source_rate) ||
+               (alsa->actual_channels != alsa->source_channels))
+       {
+               DEBUG_DVC("actual rate %d / channel %d is different "
+                       "from source rate %d / channel %d, resampling required.",
+                       alsa->actual_rate, alsa->actual_channels,
+                       alsa->source_rate, alsa->source_channels);
+       }
+       return true;
+}
+
+static boolean tsmf_alsa_play(ITSMFAudioDevice* audio, uint8* data, uint32 data_size)
+{
+       int len;
+       int error;
+       int frames;
+       uint8* end;
+       uint8* src;
+       uint8* pindex;
+       int rbytes_per_frame;
+       int sbytes_per_frame;
+       uint8* resampled_data;
+       TSMFALSAAudioDevice* alsa = (TSMFALSAAudioDevice*) audio;
+
+       DEBUG_DVC("data_size %d", data_size);
+
+       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))
+               {
+                       resampled_data = NULL;
+                       src = data;
+               }
+               else
+               {
+                       resampled_data = dsp_resample(data, alsa->bytes_per_sample,
+                               alsa->source_channels, alsa->source_rate, data_size / sbytes_per_frame,
+                               alsa->actual_channels, alsa->actual_rate, &frames);
+                       DEBUG_DVC("resampled %d frames at %d to %d frames at %d",
+                               data_size / sbytes_per_frame, alsa->source_rate, frames, alsa->actual_rate);
+                       data_size = frames * rbytes_per_frame;
+                       src = resampled_data;
+               }
+
+               pindex = src;
+               end = pindex + data_size;
+               while (pindex < end)
+               {
+                       len = end - pindex;
+                       frames = len / rbytes_per_frame;
+                       error = snd_pcm_writei(alsa->out_handle, pindex, frames);
+                       if (error == -EPIPE)
+                       {
+                               snd_pcm_recover(alsa->out_handle, error, 0);
+                               error = 0;
+                       }
+                       else if (error < 0)
+                       {
+                               DEBUG_DVC("error len %d", error);
+                               snd_pcm_close(alsa->out_handle);
+                               alsa->out_handle = 0;
+                               tsmf_alsa_open_device(alsa);
+                               break;
+                       }
+                       DEBUG_DVC("%d frames played.", error);
+                       if (error == 0)
+                               break;
+                       pindex += error * rbytes_per_frame;
+               }
+
+               if (resampled_data)
+                       xfree(resampled_data);
+       }
+       xfree(data);
+
+       return true;
+}
+
+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)
+       {
+               latency = ((uint64)frames) * 10000000LL / (uint64)alsa->actual_rate;
+       }
+       return latency;
+}
+
+static void tsmf_alsa_flush(ITSMFAudioDevice* audio)
+{
+}
+
+static void tsmf_alsa_free(ITSMFAudioDevice* audio)
+{
+       TSMFALSAAudioDevice* alsa = (TSMFALSAAudioDevice*) audio;
+
+       DEBUG_DVC("");
+
+       if (alsa->out_handle)
+       {
+               snd_pcm_drain(alsa->out_handle);
+               snd_pcm_close(alsa->out_handle);
+       }
+       xfree(alsa);
+}
+
+ITSMFAudioDevice* TSMFAudioDeviceEntry(void)
+{
+       TSMFALSAAudioDevice* alsa;
+
+       alsa = xnew(TSMFALSAAudioDevice);
+
+       alsa->iface.Open = tsmf_alsa_open;
+       alsa->iface.SetFormat = tsmf_alsa_set_format;
+       alsa->iface.Play = tsmf_alsa_play;
+       alsa->iface.GetLatency = tsmf_alsa_get_latency;
+       alsa->iface.Flush = tsmf_alsa_flush;
+       alsa->iface.Free = tsmf_alsa_free;
+
+       return (ITSMFAudioDevice*) alsa;
+}
+
diff --git a/channels/drdynvc/tsmf/ffmpeg/CMakeLists.txt b/channels/drdynvc/tsmf/ffmpeg/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ea0b101
--- /dev/null
@@ -0,0 +1,34 @@
+# FreeRDP: A Remote Desktop Protocol Client
+# FreeRDP cmake build script
+#
+# Copyright 2011 O.S. Systems Software Ltda.
+# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
+# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set(TSMF_FFMPEG_SRCS
+       tsmf_ffmpeg.c
+)
+
+include_directories(..)
+include_directories(${FFMPEG_INCLUDE_DIRS})
+
+add_library(tsmf_ffmpeg ${TSMF_FFMPEG_SRCS})
+set_target_properties(tsmf_ffmpeg PROPERTIES PREFIX "")
+
+target_link_libraries(tsmf_ffmpeg freerdp-utils)
+target_link_libraries(tsmf_ffmpeg ${FFMPEG_LIBRARIES})
+
+install(TARGETS tsmf_ffmpeg DESTINATION ${FREERDP_PLUGIN_PATH})
+
diff --git a/channels/drdynvc/tsmf/ffmpeg/tsmf_ffmpeg.c b/channels/drdynvc/tsmf/ffmpeg/tsmf_ffmpeg.c
new file mode 100644 (file)
index 0000000..4210fa0
--- /dev/null
@@ -0,0 +1,518 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Video Redirection Virtual Channel - FFmpeg Decoder
+ *
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <freerdp/utils/memory.h>
+#include <freerdp/utils/event.h>
+#include <freerdp/plugins/tsmf.h>
+#include <libavcodec/avcodec.h>
+
+#include "tsmf_constants.h"
+#include "tsmf_decoder.h"
+
+/* Compatibility with older FFmpeg */
+#if LIBAVUTIL_VERSION_MAJOR < 50
+#define AVMEDIA_TYPE_VIDEO 0
+#define AVMEDIA_TYPE_AUDIO 1
+#endif
+
+typedef struct _TSMFFFmpegDecoder
+{
+       ITSMFDecoder iface;
+
+       int media_type;
+       enum CodecID codec_id;
+       AVCodecContext* codec_context;
+       AVCodec* codec;
+       AVFrame* frame;
+       int prepared;
+
+       uint8* decoded_data;
+       uint32 decoded_size;
+       uint32 decoded_size_max;
+} TSMFFFmpegDecoder;
+
+static boolean tsmf_ffmpeg_init_context(ITSMFDecoder* decoder)
+{
+       TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
+
+       mdecoder->codec_context = avcodec_alloc_context();
+       if (!mdecoder->codec_context)
+       {
+               DEBUG_WARN("avcodec_alloc_context failed.");
+               return false;
+       }
+
+       return true;
+}
+
+static boolean tsmf_ffmpeg_init_video_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE* media_type)
+{
+       TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
+
+       mdecoder->codec_context->width = media_type->Width;
+       mdecoder->codec_context->height = media_type->Height;
+       mdecoder->codec_context->bit_rate = media_type->BitRate;
+       mdecoder->codec_context->time_base.den = media_type->SamplesPerSecond.Numerator;
+       mdecoder->codec_context->time_base.num = media_type->SamplesPerSecond.Denominator;
+
+       mdecoder->frame = avcodec_alloc_frame();
+
+       return true;
+}
+
+static boolean tsmf_ffmpeg_init_audio_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE* media_type)
+{
+       TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
+
+       mdecoder->codec_context->sample_rate = media_type->SamplesPerSecond.Numerator;
+       mdecoder->codec_context->bit_rate = media_type->BitRate;
+       mdecoder->codec_context->channels = media_type->Channels;
+       mdecoder->codec_context->block_align = media_type->BlockAlign;
+
+#ifdef AV_CPU_FLAG_SSE2
+       mdecoder->codec_context->dsp_mask = AV_CPU_FLAG_SSE2 | AV_CPU_FLAG_MMX2;
+#else
+#if LIBAVCODEC_VERSION_MAJOR < 53
+       mdecoder->codec_context->dsp_mask = FF_MM_SSE2 | FF_MM_MMXEXT;
+#else
+       mdecoder->codec_context->dsp_mask = FF_MM_SSE2 | FF_MM_MMX2;
+#endif
+#endif
+
+       return true;
+}
+
+static boolean tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE* media_type)
+{
+       TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
+       uint32 size;
+       const uint8* s;
+       uint8* p;
+
+       mdecoder->codec = avcodec_find_decoder(mdecoder->codec_id);
+       if (!mdecoder->codec)
+       {
+               DEBUG_WARN("avcodec_find_decoder failed.");
+               return false;
+       }
+
+       mdecoder->codec_context->codec_id = mdecoder->codec_id;
+       mdecoder->codec_context->codec_type = mdecoder->media_type;
+
+       if (mdecoder->media_type == AVMEDIA_TYPE_VIDEO)
+       {
+               if (!tsmf_ffmpeg_init_video_stream(decoder, media_type))
+                       return false;
+       }
+       else if (mdecoder->media_type == AVMEDIA_TYPE_AUDIO)
+       {
+               if (!tsmf_ffmpeg_init_audio_stream(decoder, media_type))
+                       return false;
+       }
+
+       if (media_type->ExtraData)
+       {
+               if (media_type->SubType == TSMF_SUB_TYPE_AVC1 &&
+                       media_type->FormatType == TSMF_FORMAT_TYPE_MPEG2VIDEOINFO)
+               {
+                       /* The extradata format that FFmpeg uses is following CodecPrivate in Matroska.
+                          See http://haali.su/mkv/codecs.pdf */
+                       mdecoder->codec_context->extradata_size = media_type->ExtraDataSize + 8;
+                       mdecoder->codec_context->extradata = xzalloc(mdecoder->codec_context->extradata_size);
+                       p = mdecoder->codec_context->extradata;
+                       *p++ = 1; /* Reserved? */
+                       *p++ = media_type->ExtraData[8]; /* Profile */
+                       *p++ = 0; /* Profile */
+                       *p++ = media_type->ExtraData[12]; /* Level */
+                       *p++ = 0xff; /* Flag? */
+                       *p++ = 0xe0 | 0x01; /* Reserved | #sps */
+                       s = media_type->ExtraData + 20;
+                       size = ((uint32)(*s)) * 256 + ((uint32)(*(s + 1)));
+                       memcpy(p, s, size + 2);
+                       s += size + 2;
+                       p += size + 2;
+                       *p++ = 1; /* #pps */
+                       size = ((uint32)(*s)) * 256 + ((uint32)(*(s + 1)));
+                       memcpy(p, s, size + 2);
+               }
+               else
+               {
+                       /* Add a padding to avoid invalid memory read in some codec */
+                       mdecoder->codec_context->extradata_size = media_type->ExtraDataSize + 8;
+                       mdecoder->codec_context->extradata = xzalloc(mdecoder->codec_context->extradata_size);
+                       memcpy(mdecoder->codec_context->extradata, media_type->ExtraData, media_type->ExtraDataSize);
+                       memset(mdecoder->codec_context->extradata + media_type->ExtraDataSize, 0, 8);
+               }
+       }
+
+       if (mdecoder->codec->capabilities & CODEC_CAP_TRUNCATED)
+               mdecoder->codec_context->flags |= CODEC_FLAG_TRUNCATED;
+
+       return true;
+}
+
+static boolean tsmf_ffmpeg_prepare(ITSMFDecoder* decoder)
+{
+       TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
+
+       if (avcodec_open(mdecoder->codec_context, mdecoder->codec) < 0)
+       {
+               DEBUG_WARN("avcodec_open failed.");
+               return false;
+       }
+
+       mdecoder->prepared = 1;
+
+       return true;
+}
+
+static boolean tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* media_type)
+{
+       TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
+
+       switch (media_type->MajorType)
+       {
+               case TSMF_MAJOR_TYPE_VIDEO:
+                       mdecoder->media_type = AVMEDIA_TYPE_VIDEO;
+                       break;
+               case TSMF_MAJOR_TYPE_AUDIO:
+                       mdecoder->media_type = AVMEDIA_TYPE_AUDIO;
+                       break;
+               default:
+                       return false;
+       }
+       switch (media_type->SubType)
+       {
+               case TSMF_SUB_TYPE_WVC1:
+                       mdecoder->codec_id = CODEC_ID_VC1;
+                       break;
+               case TSMF_SUB_TYPE_WMA2:
+                       mdecoder->codec_id = CODEC_ID_WMAV2;
+                       break;
+               case TSMF_SUB_TYPE_WMA9:
+                       mdecoder->codec_id = CODEC_ID_WMAPRO;
+                       break;
+               case TSMF_SUB_TYPE_MP3:
+                       mdecoder->codec_id = CODEC_ID_MP3;
+                       break;
+               case TSMF_SUB_TYPE_MP2A:
+                       mdecoder->codec_id = CODEC_ID_MP2;
+                       break;
+               case TSMF_SUB_TYPE_MP2V:
+                       mdecoder->codec_id = CODEC_ID_MPEG2VIDEO;
+                       break;
+               case TSMF_SUB_TYPE_WMV3:
+                       mdecoder->codec_id = CODEC_ID_WMV3;
+                       break;
+               case TSMF_SUB_TYPE_AAC:
+                       mdecoder->codec_id = CODEC_ID_AAC;
+                       /* For AAC the pFormat is a HEAACWAVEINFO struct, and the codec data
+                          is at the end of it. See
+                          http://msdn.microsoft.com/en-us/library/dd757806.aspx */
+                       if (media_type->ExtraData)
+                       {
+                               media_type->ExtraData += 12;
+                               media_type->ExtraDataSize -= 12;
+                       }
+                       break;
+               case TSMF_SUB_TYPE_H264:
+               case TSMF_SUB_TYPE_AVC1:
+                       mdecoder->codec_id = CODEC_ID_H264;
+                       break;
+               case TSMF_SUB_TYPE_AC3:
+                       mdecoder->codec_id = CODEC_ID_AC3;
+                       break;
+               default:
+                       return false;
+       }
+
+       if (!tsmf_ffmpeg_init_context(decoder))
+               return false;
+       if (!tsmf_ffmpeg_init_stream(decoder, media_type))
+               return false;
+       if (!tsmf_ffmpeg_prepare(decoder))
+               return false;
+
+       return true;
+}
+
+static boolean tsmf_ffmpeg_decode_video(ITSMFDecoder* decoder, const uint8* data, uint32 data_size, uint32 extensions)
+{
+       TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
+       int decoded;
+       int len;
+       AVFrame* frame;
+       boolean ret = true;
+
+#if LIBAVCODEC_VERSION_MAJOR < 52 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR <= 20)
+       len = avcodec_decode_video(mdecoder->codec_context, mdecoder->frame, &decoded, data, data_size);
+#else
+       {
+               AVPacket pkt;
+               av_init_packet(&pkt);
+               pkt.data = (uint8*) data;
+               pkt.size = data_size;
+               if (extensions & TSMM_SAMPLE_EXT_CLEANPOINT)
+                       pkt.flags |= AV_PKT_FLAG_KEY;
+               len = avcodec_decode_video2(mdecoder->codec_context, mdecoder->frame, &decoded, &pkt);
+       }
+#endif
+
+       if (len < 0)
+       {
+               DEBUG_WARN("data_size %d, avcodec_decode_video failed (%d)", data_size, len);
+               ret = false;
+       }
+       else if (!decoded)
+       {
+               DEBUG_WARN("data_size %d, no frame is decoded.", data_size);
+               ret = false;
+       }
+       else
+       {
+               DEBUG_DVC("linesize[0] %d linesize[1] %d linesize[2] %d linesize[3] %d "
+                       "pix_fmt %d width %d height %d",
+                       mdecoder->frame->linesize[0], mdecoder->frame->linesize[1],
+                       mdecoder->frame->linesize[2], mdecoder->frame->linesize[3],
+                       mdecoder->codec_context->pix_fmt,
+                       mdecoder->codec_context->width, mdecoder->codec_context->height);
+
+               mdecoder->decoded_size = avpicture_get_size(mdecoder->codec_context->pix_fmt,
+                       mdecoder->codec_context->width, mdecoder->codec_context->height);
+               mdecoder->decoded_data = xzalloc(mdecoder->decoded_size);
+               frame = avcodec_alloc_frame();
+               avpicture_fill((AVPicture *) frame, mdecoder->decoded_data,
+                       mdecoder->codec_context->pix_fmt,
+                       mdecoder->codec_context->width, mdecoder->codec_context->height);
+
+               av_picture_copy((AVPicture *) frame, (AVPicture *) mdecoder->frame,
+                       mdecoder->codec_context->pix_fmt,
+                       mdecoder->codec_context->width, mdecoder->codec_context->height);
+
+               av_free(frame);
+       }
+
+       return ret;
+}
+
+static boolean tsmf_ffmpeg_decode_audio(ITSMFDecoder* decoder, const uint8* data, uint32 data_size, uint32 extensions)
+{
+       TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
+       int len;
+       int frame_size;
+       uint32 src_size;
+       const uint8* src;
+       uint8* dst;
+       int dst_offset;
+
+#if 0
+       LLOGLN(0, ("tsmf_ffmpeg_decode_audio: data_size %d", data_size));
+       int i;
+       for (i = 0; i < data_size; i++)
+       {
+               LLOG(0, ("%02X ", data[i]));
+               if (i % 16 == 15)
+                       LLOG(0, ("\n"));
+       }
+       LLOG(0, ("\n"));
+#endif
+
+       if (mdecoder->decoded_size_max == 0)
+               mdecoder->decoded_size_max = AVCODEC_MAX_AUDIO_FRAME_SIZE + 16;
+       mdecoder->decoded_data = xzalloc(mdecoder->decoded_size_max);
+       /* align the memory for SSE2 needs */
+       dst = (uint8*) (((uintptr_t)mdecoder->decoded_data + 15) & ~ 0x0F);
+       dst_offset = dst - mdecoder->decoded_data;
+       src = data;
+       src_size = data_size;
+
+       while (src_size > 0)
+       {
+               /* Ensure enough space for decoding */
+               if (mdecoder->decoded_size_max - mdecoder->decoded_size < AVCODEC_MAX_AUDIO_FRAME_SIZE)
+               {
+                       mdecoder->decoded_size_max = mdecoder->decoded_size_max * 2 + 16;
+                       mdecoder->decoded_data = xrealloc(mdecoder->decoded_data, mdecoder->decoded_size_max);
+                       dst = (uint8*) (((uintptr_t)mdecoder->decoded_data + 15) & ~ 0x0F);
+                       if (dst - mdecoder->decoded_data != dst_offset)
+                       {
+                               /* re-align the memory if the alignment has changed after realloc */
+                               memmove(dst, mdecoder->decoded_data + dst_offset, mdecoder->decoded_size);
+                               dst_offset = dst - mdecoder->decoded_data;
+                       }
+                       dst += mdecoder->decoded_size;
+               }
+               frame_size = mdecoder->decoded_size_max - mdecoder->decoded_size;
+#if LIBAVCODEC_VERSION_MAJOR < 52 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR <= 20)
+               len = avcodec_decode_audio2(mdecoder->codec_context,
+                       (int16_t*) dst, &frame_size,
+                       src, src_size);
+#else
+               {
+                       AVPacket pkt;
+                       av_init_packet(&pkt);
+                       pkt.data = (uint8*) src;
+                       pkt.size = src_size;
+                       len = avcodec_decode_audio3(mdecoder->codec_context,
+                               (int16_t*) dst, &frame_size, &pkt);
+               }
+#endif
+               if (len <= 0 || frame_size <= 0)
+               {
+                       DEBUG_WARN("error decoding");
+                       break;
+               }
+               src += len;
+               src_size -= len;
+               mdecoder->decoded_size += frame_size;
+               dst += frame_size;
+       }
+
+       if (mdecoder->decoded_size == 0)
+       {
+               xfree(mdecoder->decoded_data);
+               mdecoder->decoded_data = NULL;
+       }
+       else if (dst_offset)
+       {
+               /* move the aligned decoded data to original place */
+               memmove(mdecoder->decoded_data, mdecoder->decoded_data + dst_offset, mdecoder->decoded_size);
+       }
+
+       DEBUG_DVC("data_size %d decoded_size %d",
+               data_size, mdecoder->decoded_size);
+
+       return true;
+}
+
+static boolean tsmf_ffmpeg_decode(ITSMFDecoder* decoder, const uint8* data, uint32 data_size, uint32 extensions)
+{
+       TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
+
+       if (mdecoder->decoded_data)
+       {
+               xfree(mdecoder->decoded_data);
+               mdecoder->decoded_data = NULL;
+       }
+       mdecoder->decoded_size = 0;
+
+       switch (mdecoder->media_type)
+       {
+               case AVMEDIA_TYPE_VIDEO:
+                       return tsmf_ffmpeg_decode_video(decoder, data, data_size, extensions);
+               case AVMEDIA_TYPE_AUDIO:
+                       return tsmf_ffmpeg_decode_audio(decoder, data, data_size, extensions);
+               default:
+                       DEBUG_WARN("unknown media type.");
+                       return false;
+       }
+}
+
+static uint8* tsmf_ffmpeg_get_decoded_data(ITSMFDecoder* decoder, uint32* size)
+{
+       TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
+       uint8* buf;
+
+       *size = mdecoder->decoded_size;
+       buf = mdecoder->decoded_data;
+       mdecoder->decoded_data = NULL;
+       mdecoder->decoded_size = 0;
+       return buf;
+}
+
+static uint32 tsmf_ffmpeg_get_decoded_format(ITSMFDecoder* decoder)
+{
+       TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
+
+       switch (mdecoder->codec_context->pix_fmt)
+       {
+               case PIX_FMT_YUV420P:
+                       return RDP_PIXFMT_I420;
+
+               default:
+                       DEBUG_WARN("unsupported pixel format %u",
+                               mdecoder->codec_context->pix_fmt);
+                       return (uint32) -1;
+       }
+}
+
+static boolean tsmf_ffmpeg_get_decoded_dimension(ITSMFDecoder* decoder, uint32* width, uint32* height)
+{
+       TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
+
+       if (mdecoder->codec_context->width > 0 && mdecoder->codec_context->height > 0)
+       {
+               *width = mdecoder->codec_context->width;
+               *height = mdecoder->codec_context->height;
+               return true;
+       }
+       else
+       {
+               return false;
+       }
+}
+
+static void tsmf_ffmpeg_free(ITSMFDecoder* decoder)
+{
+       TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
+
+       if (mdecoder->frame)
+               av_free(mdecoder->frame);
+       if (mdecoder->decoded_data)
+               xfree(mdecoder->decoded_data);
+       if (mdecoder->codec_context)
+       {
+               if (mdecoder->prepared)
+                       avcodec_close(mdecoder->codec_context);
+               if (mdecoder->codec_context->extradata)
+                       xfree(mdecoder->codec_context->extradata);
+               av_free(mdecoder->codec_context);
+       }
+       xfree(decoder);
+}
+
+static boolean initialized = false;
+
+ITSMFDecoder*
+TSMFDecoderEntry(void)
+{
+       TSMFFFmpegDecoder * decoder;
+
+       if (!initialized)
+       {
+               avcodec_init();
+               avcodec_register_all();
+               initialized = true;
+       }
+
+       decoder = xnew(TSMFFFmpegDecoder);
+
+       decoder->iface.SetFormat = tsmf_ffmpeg_set_format;
+       decoder->iface.Decode = tsmf_ffmpeg_decode;
+       decoder->iface.GetDecodedData = tsmf_ffmpeg_get_decoded_data;
+       decoder->iface.GetDecodedFormat = tsmf_ffmpeg_get_decoded_format;
+       decoder->iface.GetDecodedDimension = tsmf_ffmpeg_get_decoded_dimension;
+       decoder->iface.Free = tsmf_ffmpeg_free;
+
+       return (ITSMFDecoder*) decoder;
+}
+
diff --git a/channels/drdynvc/tsmf/pulse/CMakeLists.txt b/channels/drdynvc/tsmf/pulse/CMakeLists.txt
new file mode 100644 (file)
index 0000000..373d4d3
--- /dev/null
@@ -0,0 +1,34 @@
+# FreeRDP: A Remote Desktop Protocol Client
+# FreeRDP cmake build script
+#
+# Copyright 2011 O.S. Systems Software Ltda.
+# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
+# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set(TSMF_PULSE_SRCS
+       tsmf_pulse.c
+)
+
+include_directories(..)
+include_directories(${PULSE_INCLUDE_DIRS})
+
+add_library(tsmf_pulse ${TSMF_PULSE_SRCS})
+set_target_properties(tsmf_pulse PROPERTIES PREFIX "")
+
+target_link_libraries(tsmf_pulse freerdp-utils)
+target_link_libraries(tsmf_pulse ${PULSE_LIBRARIES})
+
+install(TARGETS tsmf_pulse DESTINATION ${FREERDP_PLUGIN_PATH})
+
diff --git a/channels/drdynvc/tsmf/pulse/tsmf_pulse.c b/channels/drdynvc/tsmf/pulse/tsmf_pulse.c
new file mode 100644 (file)
index 0000000..de3c901
--- /dev/null
@@ -0,0 +1,402 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Video Redirection Virtual Channel - PulseAudio Device
+ *
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pulse/pulseaudio.h>
+#include <freerdp/utils/memory.h>
+
+#include "tsmf_audio.h"
+
+typedef struct _TSMFPulseAudioDevice
+{
+       ITSMFAudioDevice iface;
+
+       char device[32];
+       pa_threaded_mainloop* mainloop;
+       pa_context* context;
+       pa_sample_spec sample_spec;
+       pa_stream* stream;
+} TSMFPulseAudioDevice;
+
+static void tsmf_pulse_context_state_callback(pa_context* context, void* userdata)
+{
+       TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata;
+       pa_context_state_t state;
+
+       state = pa_context_get_state(context);
+       switch (state)
+       {
+               case PA_CONTEXT_READY:
+                       DEBUG_DVC("PA_CONTEXT_READY");
+                       pa_threaded_mainloop_signal(pulse->mainloop, 0);
+                       break;
+
+               case PA_CONTEXT_FAILED:
+               case PA_CONTEXT_TERMINATED:
+                       DEBUG_DVC("state %d", (int)state);
+                       pa_threaded_mainloop_signal(pulse->mainloop, 0);
+                       break;
+
+               default:
+                       DEBUG_DVC("state %d", (int)state);
+                       break;
+       }
+}
+
+static boolean tsmf_pulse_connect(TSMFPulseAudioDevice* pulse)
+{
+       pa_context_state_t state;
+
+       if (!pulse->context)
+               return false;
+
+       if (pa_context_connect(pulse->context, NULL, 0, NULL))
+       {
+               DEBUG_WARN("pa_context_connect failed (%d)",
+                       pa_context_errno(pulse->context));
+               return false;
+       }
+       pa_threaded_mainloop_lock(pulse->mainloop);
+       if (pa_threaded_mainloop_start(pulse->mainloop) < 0)
+       {
+               pa_threaded_mainloop_unlock(pulse->mainloop);
+               DEBUG_WARN("pa_threaded_mainloop_start failed (%d)",
+                       pa_context_errno(pulse->context));
+               return false;
+       }
+       for (;;)
+       {
+               state = pa_context_get_state(pulse->context);
+               if (state == PA_CONTEXT_READY)
+                       break;
+               if (!PA_CONTEXT_IS_GOOD(state))
+               {
+                       DEBUG_DVC("bad context state (%d)",
+                               pa_context_errno(pulse->context));
+                       break;
+               }
+               pa_threaded_mainloop_wait(pulse->mainloop);
+       }
+       pa_threaded_mainloop_unlock(pulse->mainloop);
+       if (state == PA_CONTEXT_READY)
+       {
+               DEBUG_DVC("connected");
+               return true;
+       }
+       else
+       {
+               pa_context_disconnect(pulse->context);
+               return false;
+       }
+}
+
+static boolean tsmf_pulse_open(ITSMFAudioDevice* audio, const char* device)
+{
+       TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio;
+
+       if (device)
+       {
+               strcpy(pulse->device, device);
+       }
+
+       pulse->mainloop = pa_threaded_mainloop_new();
+       if (!pulse->mainloop)
+       {
+               DEBUG_WARN("pa_threaded_mainloop_new failed");
+               return false;
+       }
+       pulse->context = pa_context_new(pa_threaded_mainloop_get_api(pulse->mainloop), "freerdp");
+       if (!pulse->context)
+       {
+               DEBUG_WARN("pa_context_new failed");
+               return false;
+       }
+       pa_context_set_state_callback(pulse->context, tsmf_pulse_context_state_callback, pulse);
+       if (tsmf_pulse_connect(pulse))
+       {
+               DEBUG_WARN("tsmf_pulse_connect failed");
+               return false;
+       }
+
+       DEBUG_DVC("open device %s", pulse->device);
+       return true;
+}
+
+static void tsmf_pulse_stream_success_callback(pa_stream* stream, int success, void* userdata)
+{
+       TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata;
+
+       pa_threaded_mainloop_signal(pulse->mainloop, 0);
+}
+
+static void tsmf_pulse_wait_for_operation(TSMFPulseAudioDevice* pulse, pa_operation* operation)
+{
+       if (operation == NULL)
+               return;
+       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)
+{
+       TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata;
+       pa_stream_state_t state;
+
+       state = pa_stream_get_state(stream);
+       switch (state)
+       {
+               case PA_STREAM_READY:
+                       DEBUG_DVC("PA_STREAM_READY");
+                       pa_threaded_mainloop_signal (pulse->mainloop, 0);
+                       break;
+
+               case PA_STREAM_FAILED:
+               case PA_STREAM_TERMINATED:
+                       DEBUG_DVC("state %d", (int)state);
+                       pa_threaded_mainloop_signal (pulse->mainloop, 0);
+                       break;
+
+               default:
+                       DEBUG_DVC("state %d", (int)state);
+                       break;
+       }
+}
+
+static void tsmf_pulse_stream_request_callback(pa_stream* stream, size_t length, void* userdata)
+{
+       TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata;
+
+       DEBUG_DVC("%d", (int) length);
+
+       pa_threaded_mainloop_signal(pulse->mainloop, 0);
+}
+
+static boolean tsmf_pulse_close_stream(TSMFPulseAudioDevice* pulse)
+{
+       if (!pulse->context || !pulse->stream)
+               return false;
+
+       DEBUG_DVC("");
+
+       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_disconnect(pulse->stream);
+       pa_stream_unref(pulse->stream);
+       pulse->stream = NULL;
+       pa_threaded_mainloop_unlock(pulse->mainloop);
+
+       return true;
+}
+
+static boolean tsmf_pulse_open_stream(TSMFPulseAudioDevice* pulse)
+{
+       pa_stream_state_t state;
+       pa_buffer_attr buffer_attr = { 0 };
+
+       if (!pulse->context)
+               return false;
+
+       DEBUG_DVC("");
+
+       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);
+               DEBUG_WARN("pa_stream_new failed (%d)",
+                       pa_context_errno(pulse->context));
+               return false;
+       }
+       pa_stream_set_state_callback(pulse->stream,
+               tsmf_pulse_stream_state_callback, pulse);
+       pa_stream_set_write_callback(pulse->stream,
+               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_t) -1;
+       buffer_attr.minreq = (uint32_t) -1;
+       buffer_attr.fragsize = (uint32_t) -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);
+               DEBUG_WARN("pa_stream_connect_playback failed (%d)",
+                       pa_context_errno(pulse->context));
+               return false;
+       }
+
+       for (;;)
+       {
+               state = pa_stream_get_state(pulse->stream);
+               if (state == PA_STREAM_READY)
+                       break;
+               if (!PA_STREAM_IS_GOOD(state))
+               {
+                       DEBUG_WARN("bad stream state (%d)",
+                               pa_context_errno(pulse->context));
+                       break;
+               }
+               pa_threaded_mainloop_wait(pulse->mainloop);
+       }
+       pa_threaded_mainloop_unlock(pulse->mainloop);
+       if (state == PA_STREAM_READY)
+       {
+               DEBUG_DVC("connected");
+               return true;
+       }
+       else
+       {
+               tsmf_pulse_close_stream(pulse);
+               return false;
+       }
+}
+
+static boolean tsmf_pulse_set_format(ITSMFAudioDevice* audio,
+       uint32 sample_rate, uint32 channels, uint32 bits_per_sample)
+{
+       TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio;
+
+       DEBUG_DVC("sample_rate %d channels %d bits_per_sample %d",
+               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 boolean tsmf_pulse_play(ITSMFAudioDevice* audio, uint8* data, uint32 data_size)
+{
+       TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio;
+       uint8* src;
+       int len;
+       int ret;
+
+       DEBUG_DVC("data_size %d", data_size);
+
+       if (pulse->stream)
+       {
+               pa_threaded_mainloop_lock(pulse->mainloop);
+
+               src = data;
+               while (data_size > 0)
+               {
+                       while ((len = pa_stream_writable_size(pulse->stream)) == 0)
+                       {
+                               DEBUG_DVC("waiting");
+                               pa_threaded_mainloop_wait(pulse->mainloop);
+                       }
+                       if (len < 0)
+                               break;
+                       if (len > data_size)
+                               len = data_size;
+                       ret = pa_stream_write(pulse->stream, src, len, NULL, 0LL, PA_SEEK_RELATIVE);
+                       if (ret < 0)
+                       {
+                               DEBUG_DVC("pa_stream_write failed (%d)",
+                                       pa_context_errno(pulse->context));
+                               break;
+                       }
+                       src += len;
+                       data_size -= len;
+               }
+
+               pa_threaded_mainloop_unlock(pulse->mainloop);
+       }
+       xfree(data);
+
+       return true;
+}
+
+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)
+       {
+               latency = ((uint64)usec) * 10LL;
+       }
+       return latency;
+}
+
+static void tsmf_pulse_flush(ITSMFAudioDevice* 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_threaded_mainloop_unlock(pulse->mainloop);
+}
+
+static void tsmf_pulse_free(ITSMFAudioDevice* audio)
+{
+       TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio;
+
+       DEBUG_DVC("");
+
+       tsmf_pulse_close_stream(pulse);
+       if (pulse->mainloop)
+       {
+               pa_threaded_mainloop_stop(pulse->mainloop);
+       }
+       if (pulse->context)
+       {
+               pa_context_disconnect(pulse->context);
+               pa_context_unref(pulse->context);
+               pulse->context = NULL;
+       }
+       if (pulse->mainloop)
+       {
+               pa_threaded_mainloop_free(pulse->mainloop);
+               pulse->mainloop = NULL;
+       }
+       xfree(pulse);
+}
+
+ITSMFAudioDevice* TSMFAudioDeviceEntry(void)
+{
+       TSMFPulseAudioDevice* pulse;
+
+       pulse = xnew(TSMFPulseAudioDevice);
+
+       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;
+}
+
diff --git a/channels/drdynvc/tsmf/tsmf_audio.c b/channels/drdynvc/tsmf/tsmf_audio.c
new file mode 100644 (file)
index 0000000..5a1a145
--- /dev/null
@@ -0,0 +1,80 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Video Redirection Virtual Channel - Audio Device Manager
+ *
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <freerdp/utils/memory.h>
+#include <freerdp/utils/load_plugin.h>
+
+#include "tsmf_audio.h"
+
+static ITSMFAudioDevice* tsmf_load_audio_device_by_name(const char* name, const char* device)
+{
+       ITSMFAudioDevice* audio;
+       TSMF_AUDIO_DEVICE_ENTRY entry;
+       char* fullname;
+
+       if (strrchr(name, '.') != NULL)
+               entry = (TSMF_AUDIO_DEVICE_ENTRY) freerdp_load_plugin(name, TSMF_AUDIO_DEVICE_EXPORT_FUNC_NAME);
+       else
+       {
+               fullname = xzalloc(strlen(name) + 6);
+               strcpy(fullname, "tsmf_");
+               strcat(fullname, name);
+               entry = (TSMF_AUDIO_DEVICE_ENTRY) freerdp_load_plugin(fullname, TSMF_AUDIO_DEVICE_EXPORT_FUNC_NAME);
+               xfree(fullname);
+       }
+       if (entry == NULL)
+       {
+               return NULL;
+       }
+
+       audio = entry();
+       if (audio == NULL)
+       {
+               DEBUG_WARN("failed to call export function in %s", name);
+               return NULL;
+       }
+       if (!audio->Open(audio, device))
+       {
+               audio->Free(audio);
+               audio = NULL;
+       }
+       return audio;
+}
+
+ITSMFAudioDevice* tsmf_load_audio_device(const char* name, const char* device)
+{
+       ITSMFAudioDevice* audio;
+
+       if (name)
+       {
+               audio = tsmf_load_audio_device_by_name(name, device);
+       }
+       else
+       {
+               audio = tsmf_load_audio_device_by_name("pulse", device);
+               if (!audio)
+                       audio = tsmf_load_audio_device_by_name("alsa", device);
+       }
+
+       return audio;
+}
+
diff --git a/channels/drdynvc/tsmf/tsmf_audio.h b/channels/drdynvc/tsmf/tsmf_audio.h
new file mode 100644 (file)
index 0000000..af00759
--- /dev/null
@@ -0,0 +1,49 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Video Redirection Virtual Channel - Audio Device Manager
+ *
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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 __TSMF_AUDIO_H
+#define __TSMF_AUDIO_H
+
+#include "drdynvc_types.h"
+
+typedef struct _ITSMFAudioDevice ITSMFAudioDevice;
+
+struct _ITSMFAudioDevice
+{
+       /* Open the audio device. */
+       boolean (*Open) (ITSMFAudioDevice* audio, const char* device);
+       /* Set the audio data format. */
+       boolean (*SetFormat) (ITSMFAudioDevice* audio, uint32 sample_rate, uint32 channels, uint32 bits_per_sample);
+       /* Play audio data. */
+       boolean (*Play) (ITSMFAudioDevice* audio, uint8* data, uint32 data_size);
+       /* Get the latency of the last written sample, in 100ns */
+       uint64 (*GetLatency) (ITSMFAudioDevice* audio);
+       /* Flush queued audio data */
+       void (*Flush) (ITSMFAudioDevice* audio);
+       /* Free the audio device */
+       void (*Free) (ITSMFAudioDevice* audio);
+};
+
+#define TSMF_AUDIO_DEVICE_EXPORT_FUNC_NAME "TSMFAudioDeviceEntry"
+typedef ITSMFAudioDevice* (*TSMF_AUDIO_DEVICE_ENTRY) (void);
+
+ITSMFAudioDevice* tsmf_load_audio_device(const char* name, const char* device);
+
+#endif
+
diff --git a/channels/drdynvc/tsmf/tsmf_codec.c b/channels/drdynvc/tsmf/tsmf_codec.c
new file mode 100644 (file)
index 0000000..bd5a317
--- /dev/null
@@ -0,0 +1,407 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Video Redirection Virtual Channel - Codec
+ *
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <freerdp/utils/stream.h>
+#include <freerdp/utils/hexdump.h>
+
+#include "drdynvc_types.h"
+#include "tsmf_constants.h"
+#include "tsmf_types.h"
+
+#include "tsmf_codec.h"
+
+typedef struct _TSMFMediaTypeMap
+{
+       uint8 guid[16];
+       const char* name;
+       int type;
+} TSMFMediaTypeMap;
+
+static const TSMFMediaTypeMap tsmf_major_type_map[] =
+{
+       /* 73646976-0000-0010-8000-00AA00389B71 */
+       {
+               { 0x76, 0x69, 0x64, 0x73, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
+               "MEDIATYPE_Video",
+               TSMF_MAJOR_TYPE_VIDEO
+       },
+
+       /* 73647561-0000-0010-8000-00AA00389B71 */
+       {
+               { 0x61, 0x75, 0x64, 0x73, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
+               "MEDIATYPE_Audio",
+               TSMF_MAJOR_TYPE_AUDIO
+       },
+
+       {
+               { 0 },
+               "Unknown",
+               TSMF_MAJOR_TYPE_UNKNOWN
+       }
+};
+
+static const TSMFMediaTypeMap tsmf_sub_type_map[] =
+{
+       /* 31435657-0000-0010-8000-00AA00389B71 */
+       {
+               { 0x57, 0x56, 0x43, 0x31, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
+               "MEDIASUBTYPE_WVC1",
+               TSMF_SUB_TYPE_WVC1
+       },
+
+       /* 00000161-0000-0010-8000-00AA00389B71 */
+       {
+               { 0x61, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
+               "MEDIASUBTYPE_WMAudioV2", /* V7, V8 has the same GUID */
+               TSMF_SUB_TYPE_WMA2
+       },
+
+       /* 00000162-0000-0010-8000-00AA00389B71 */
+       {
+               { 0x62, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
+               "MEDIASUBTYPE_WMAudioV9",
+               TSMF_SUB_TYPE_WMA9
+       },
+
+       /* 00000055-0000-0010-8000-00AA00389B71 */
+       {
+               { 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
+               "MEDIASUBTYPE_MP3",
+               TSMF_SUB_TYPE_MP3
+       },
+
+       /* E06D802B-DB46-11CF-B4D1-00805F6CBBEA */
+       {
+               { 0x2B, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA },
+               "MEDIASUBTYPE_MPEG2_AUDIO",
+               TSMF_SUB_TYPE_MP2A
+       },
+
+       /* E06D8026-DB46-11CF-B4D1-00805F6CBBEA */
+       {
+               { 0x26, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA },
+               "MEDIASUBTYPE_MPEG2_VIDEO",
+               TSMF_SUB_TYPE_MP2V
+       },
+
+       /* 33564D57-0000-0010-8000-00AA00389B71 */
+       {
+               { 0x57, 0x4D, 0x56, 0x33, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
+               "MEDIASUBTYPE_WMV3",
+               TSMF_SUB_TYPE_WMV3
+       },
+
+       /* 00001610-0000-0010-8000-00AA00389B71 */
+       {
+               { 0x10, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
+               "MEDIASUBTYPE_MPEG_HEAAC",
+               TSMF_SUB_TYPE_AAC
+       },
+
+       /* 34363248-0000-0010-8000-00AA00389B71 */
+       {
+               { 0x48, 0x32, 0x36, 0x34, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
+               "MEDIASUBTYPE_H264",
+               TSMF_SUB_TYPE_H264
+       },
+
+       /* 31435641-0000-0010-8000-00AA00389B71 */
+       {
+               { 0x41, 0x56, 0x43, 0x31, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
+               "MEDIASUBTYPE_AVC1",
+               TSMF_SUB_TYPE_AVC1
+       },
+
+       /* E06D802C-DB46-11CF-B4D1-00805F6CBBEA */
+       {
+               { 0x2C, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA },
+               "MEDIASUBTYPE_DOLBY_AC3",
+               TSMF_SUB_TYPE_AC3
+       },
+
+       {
+               { 0 },
+               "Unknown",
+               TSMF_SUB_TYPE_UNKNOWN
+       }
+
+};
+
+static const TSMFMediaTypeMap tsmf_format_type_map[] =
+{
+       /* AED4AB2D-7326-43CB-9464-C879CAB9C43D */
+       {
+               { 0x2D, 0xAB, 0xD4, 0xAE, 0x26, 0x73, 0xCB, 0x43, 0x94, 0x64, 0xC8, 0x79, 0xCA, 0xB9, 0xC4, 0x3D },
+               "FORMAT_MFVideoFormat",
+               TSMF_FORMAT_TYPE_MFVIDEOFORMAT
+       },
+
+       /* 05589F81-C356-11CE-BF01-00AA0055595A */
+       {
+               { 0x81, 0x9F, 0x58, 0x05, 0x56, 0xC3, 0xCE, 0x11, 0xBF, 0x01, 0x00, 0xAA, 0x00, 0x55, 0x59, 0x5A },
+               "FORMAT_WaveFormatEx",
+               TSMF_FORMAT_TYPE_WAVEFORMATEX
+       },
+
+       /* E06D80E3-DB46-11CF-B4D1-00805F6CBBEA */
+       {
+               { 0xE3, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA },
+               "FORMAT_MPEG2_VIDEO",
+               TSMF_FORMAT_TYPE_MPEG2VIDEOINFO
+       },
+
+       /* F72A76A0-EB0A-11D0-ACE4-0000C0CC16BA */
+       {
+               { 0xA0, 0x76, 0x2A, 0xF7, 0x0A, 0xEB, 0xD0, 0x11, 0xAC, 0xE4, 0x00, 0x00, 0xC0, 0xCC, 0x16, 0xBA },
+               "FORMAT_VideoInfo2",
+               TSMF_FORMAT_TYPE_VIDEOINFO2
+       },
+
+       {
+               { 0 },
+               "Unknown",
+               TSMF_FORMAT_TYPE_UNKNOWN
+       }
+};
+
+static void tsmf_print_guid(const uint8* guid)
+{
+#ifdef WITH_DEBUG_DVC
+       int i;
+
+       for (i = 3; i >= 0; i--)
+               printf("%02X", guid[i]);
+       printf("-");
+       for (i = 5; i >= 4; i--)
+               printf("%02X", guid[i]);
+       printf("-");
+       for (i = 7; i >= 6; i--)
+               printf("%02X", guid[i]);
+       printf("-");
+       for (i = 8; i < 16; i++)
+       {
+               printf("%02X", guid[i]);
+               if (i == 9)
+                       printf("-");
+       }
+       printf("\n");
+#endif
+}
+
+/* http://msdn.microsoft.com/en-us/library/dd318229.aspx */
+static uint32 tsmf_codec_parse_BITMAPINFOHEADER(TS_AM_MEDIA_TYPE* mediatype, STREAM* s, boolean bypass)
+{
+       uint32 biSize;
+       uint32 biWidth;
+       uint32 biHeight;
+
+       stream_read_uint32(s, biSize);
+       stream_read_uint32(s, biWidth);
+       stream_read_uint32(s, biHeight);
+       stream_seek(s, 28);
+
+       if (mediatype->Width == 0)
+               mediatype->Width = biWidth;
+       if (mediatype->Height == 0)
+               mediatype->Height = biHeight;
+       /* Assume there will be no color table for video? */
+
+       if (bypass && biSize > 40)
+               stream_seek(s, biSize - 40);
+
+       return (bypass ? biSize : 40);
+}
+
+/* http://msdn.microsoft.com/en-us/library/dd407326.aspx */
+static uint32 tsmf_codec_parse_VIDEOINFOHEADER2(TS_AM_MEDIA_TYPE* mediatype, STREAM* s)
+{
+       uint64 AvgTimePerFrame;
+
+       /* VIDEOINFOHEADER2.rcSource, RECT(LONG left, LONG top, LONG right, LONG bottom) */
+       stream_seek_uint32(s);
+       stream_seek_uint32(s);
+       stream_read_uint32(s, mediatype->Width);
+       stream_read_uint32(s, mediatype->Height);
+       /* VIDEOINFOHEADER2.rcTarget */
+       stream_seek(s, 16);
+       /* VIDEOINFOHEADER2.dwBitRate */
+       stream_read_uint32(s, mediatype->BitRate);
+       /* VIDEOINFOHEADER2.dwBitErrorRate */
+       stream_seek_uint32(s);
+       /* VIDEOINFOHEADER2.AvgTimePerFrame */
+       stream_read_uint64(s, AvgTimePerFrame);
+       mediatype->SamplesPerSecond.Numerator = 1000000;
+       mediatype->SamplesPerSecond.Denominator = (int)(AvgTimePerFrame / 10LL);
+       /* Remaining fields before bmiHeader */
+       stream_seek(s, 24);
+
+       return 72;
+}
+
+boolean tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, STREAM* s)
+{
+       int i;
+       uint32 cbFormat;
+       boolean ret = true;
+
+       memset(mediatype, 0, sizeof(TS_AM_MEDIA_TYPE));
+
+       /* MajorType */
+       DEBUG_DVC("MajorType:");
+       tsmf_print_guid(stream_get_tail(s));
+       for (i = 0; tsmf_major_type_map[i].type != TSMF_MAJOR_TYPE_UNKNOWN; i++)
+       {
+               if (memcmp(tsmf_major_type_map[i].guid, stream_get_tail(s), 16) == 0)
+                       break;
+       }
+       mediatype->MajorType = tsmf_major_type_map[i].type;
+       if (mediatype->MajorType == TSMF_MAJOR_TYPE_UNKNOWN)
+               ret = false;
+       DEBUG_DVC("MajorType %s", tsmf_major_type_map[i].name);
+       stream_seek(s, 16);
+
+       /* SubType */
+       DEBUG_DVC("SubType:");
+       tsmf_print_guid(stream_get_tail(s));
+       for (i = 0; tsmf_sub_type_map[i].type != TSMF_SUB_TYPE_UNKNOWN; i++)
+       {
+               if (memcmp(tsmf_sub_type_map[i].guid, stream_get_tail(s), 16) == 0)
+                       break;
+       }
+       mediatype->SubType = tsmf_sub_type_map[i].type;
+       if (mediatype->SubType == TSMF_SUB_TYPE_UNKNOWN)
+               ret = false;
+       DEBUG_DVC("SubType %s", tsmf_sub_type_map[i].name);
+       stream_seek(s, 16);
+
+       /* bFixedSizeSamples, bTemporalCompression, SampleSize */
+       stream_seek(s, 12);
+
+       /* FormatType */
+       DEBUG_DVC("FormatType:");
+       tsmf_print_guid(stream_get_tail(s));
+       for (i = 0; tsmf_format_type_map[i].type != TSMF_FORMAT_TYPE_UNKNOWN; i++)
+       {
+               if (memcmp(tsmf_format_type_map[i].guid, stream_get_tail(s), 16) == 0)
+                       break;
+       }
+       mediatype->FormatType = tsmf_format_type_map[i].type;
+       if (mediatype->FormatType == TSMF_FORMAT_TYPE_UNKNOWN)
+               ret = false;
+       DEBUG_DVC("FormatType %s", tsmf_format_type_map[i].name);
+       stream_seek(s, 16);
+
+       /* cbFormat */
+       stream_read_uint32(s, cbFormat);
+       DEBUG_DVC("cbFormat %d", cbFormat);
+
+#ifdef WITH_DEBUG_DVC
+       freerdp_hexdump(stream_get_tail(s), cbFormat);
+#endif
+
+       switch (mediatype->FormatType)
+       {
+               case TSMF_FORMAT_TYPE_MFVIDEOFORMAT:
+                       /* http://msdn.microsoft.com/en-us/library/aa473808.aspx */
+
+                       stream_seek(s, 8); /* dwSize and ? */
+                       stream_read_uint32(s, mediatype->Width); /* videoInfo.dwWidth */
+                       stream_read_uint32(s, mediatype->Height); /* videoInfo.dwHeight */
+                       stream_seek(s, 32);
+                       /* videoInfo.FramesPerSecond */
+                       stream_read_uint32(s, mediatype->SamplesPerSecond.Numerator);
+                       stream_read_uint32(s, mediatype->SamplesPerSecond.Denominator);
+                       stream_seek(s, 80);
+                       stream_read_uint32(s, mediatype->BitRate); /* compressedInfo.AvgBitrate */
+                       stream_seek(s, 36);
+
+                       if (cbFormat > 176)
+                       {
+                               mediatype->ExtraDataSize = cbFormat - 176;
+                               mediatype->ExtraData = stream_get_tail(s);
+                       }
+                       break;
+
+               case TSMF_FORMAT_TYPE_WAVEFORMATEX:
+                       /* http://msdn.microsoft.com/en-us/library/dd757720.aspx */
+
+                       stream_seek_uint16(s);
+                       stream_read_uint16(s, mediatype->Channels);
+                       stream_read_uint32(s, mediatype->SamplesPerSecond.Numerator);
+                       mediatype->SamplesPerSecond.Denominator = 1;
+                       stream_read_uint32(s, mediatype->BitRate);
+                       mediatype->BitRate *= 8;
+                       stream_read_uint16(s, mediatype->BlockAlign);
+                       stream_read_uint16(s, mediatype->BitsPerSample);
+                       stream_read_uint16(s, mediatype->ExtraDataSize);
+                       if (mediatype->ExtraDataSize > 0)
+                               mediatype->ExtraData = stream_get_tail(s);
+                       
+                       break;
+
+               case TSMF_FORMAT_TYPE_MPEG2VIDEOINFO:
+                       /* http://msdn.microsoft.com/en-us/library/dd390707.aspx */
+
+                       i = tsmf_codec_parse_VIDEOINFOHEADER2(mediatype, s);
+                       i += tsmf_codec_parse_BITMAPINFOHEADER(mediatype, s, true);
+                       if (cbFormat > i)
+                       {
+                               mediatype->ExtraDataSize = cbFormat - i;
+                               mediatype->ExtraData = stream_get_tail(s);
+                       }
+                       break;
+
+               case TSMF_FORMAT_TYPE_VIDEOINFO2:
+                       i = tsmf_codec_parse_VIDEOINFOHEADER2(mediatype, s);
+                       i += tsmf_codec_parse_BITMAPINFOHEADER(mediatype, s, false);
+                       if (cbFormat > i)
+                       {
+                               mediatype->ExtraDataSize = cbFormat - i;
+                               mediatype->ExtraData = stream_get_tail(s);
+                       }
+                       break;
+
+               default:
+                       break;
+       }
+
+       if (mediatype->SamplesPerSecond.Numerator == 0)
+               mediatype->SamplesPerSecond.Numerator = 1;
+       if (mediatype->SamplesPerSecond.Denominator == 0)
+               mediatype->SamplesPerSecond.Denominator = 1;
+
+       return ret;
+}
+
+boolean tsmf_codec_check_media_type(STREAM* s)
+{
+       uint8* m;
+       boolean ret;
+       TS_AM_MEDIA_TYPE mediatype;
+
+       stream_get_mark(s, m);
+       ret = tsmf_codec_parse_media_type(&mediatype, s);
+       stream_set_mark(s, m);
+
+       return ret;
+}
+
diff --git a/channels/drdynvc/tsmf/tsmf_codec.h b/channels/drdynvc/tsmf/tsmf_codec.h
new file mode 100644 (file)
index 0000000..eb6bbea
--- /dev/null
@@ -0,0 +1,29 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Video Redirection Virtual Channel - Codec
+ *
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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 __TSMF_CODEC
+#define __TSMF_CODEC
+
+#include "tsmf_types.h"
+
+boolean tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, STREAM* s);
+boolean tsmf_codec_check_media_type(STREAM* s);
+
+#endif
+
diff --git a/channels/drdynvc/tsmf/tsmf_constants.h b/channels/drdynvc/tsmf/tsmf_constants.h
new file mode 100644 (file)
index 0000000..e836dd7
--- /dev/null
@@ -0,0 +1,120 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Video Redirection Virtual Channel - Constants
+ *
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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 __TSMF_CONSTANTS_H
+#define __TSMF_CONSTANTS_H
+
+#define GUID_SIZE 16
+#define TSMF_BUFFER_PADDING_SIZE 8
+
+/* Interface IDs defined in [MS-RDPEV]. There's no constant names in the MS
+   documentation, so we create them on our own. */
+#define TSMF_INTERFACE_DEFAULT                  0x00000000
+#define TSMF_INTERFACE_CLIENT_NOTIFICATIONS     0x00000001
+#define TSMF_INTERFACE_CAPABILITIES             0x00000002
+
+/* Interface ID Mask */
+#define STREAM_ID_STUB      0x80000000
+#define STREAM_ID_PROXY     0x40000000
+#define STREAM_ID_NONE      0x00000000
+
+/* Functon ID */
+/* Common IDs for all interfaces are as follows. */
+#define RIMCALL_RELEASE                     0x00000001
+#define RIMCALL_QUERYINTERFACE              0x00000002
+/* Capabilities Negotiator Interface IDs are as follows. */
+#define RIM_EXCHANGE_CAPABILITY_REQUEST     0x00000100
+/* The Client Notifications Interface ID is as follows. */
+#define PLAYBACK_ACK                        0x00000100
+#define CLIENT_EVENT_NOTIFICATION           0x00000101
+/* Server Data Interface IDs are as follows. */
+#define EXCHANGE_CAPABILITIES_REQ           0x00000100
+#define SET_CHANNEL_PARAMS                  0x00000101
+#define ADD_STREAM                          0x00000102
+#define ON_SAMPLE                           0x00000103
+#define SET_VIDEO_WINDOW                    0x00000104
+#define ON_NEW_PRESENTATION                 0x00000105
+#define SHUTDOWN_PRESENTATION_REQ           0x00000106
+#define SET_TOPOLOGY_REQ                    0x00000107
+#define CHECK_FORMAT_SUPPORT_REQ            0x00000108
+#define ON_PLAYBACK_STARTED                 0x00000109
+#define ON_PLAYBACK_PAUSED                  0x0000010a
+#define ON_PLAYBACK_STOPPED                 0x0000010b
+#define ON_PLAYBACK_RESTARTED               0x0000010c
+#define ON_PLAYBACK_RATE_CHANGED            0x0000010d
+#define ON_FLUSH                            0x0000010e
+#define ON_STREAM_VOLUME                    0x0000010f
+#define ON_CHANNEL_VOLUME                   0x00000110
+#define ON_END_OF_STREAM                    0x00000111
+#define SET_ALLOCATOR                       0x00000112
+#define NOTIFY_PREROLL                      0x00000113
+#define UPDATE_GEOMETRY_INFO                0x00000114
+#define REMOVE_STREAM                       0x00000115
+
+/* Supported platform */
+#define MMREDIR_CAPABILITY_PLATFORM_MF      0x00000001
+#define MMREDIR_CAPABILITY_PLATFORM_DSHOW   0x00000002
+#define MMREDIR_CAPABILITY_PLATFORM_OTHER   0x00000004
+
+/* TSMM_CLIENT_EVENT Constants */
+#define TSMM_CLIENT_EVENT_ENDOFSTREAM       0x0064
+#define TSMM_CLIENT_EVENT_STOP_COMPLETED    0x00C8
+#define TSMM_CLIENT_EVENT_START_COMPLETED   0x00C9
+#define TSMM_CLIENT_EVENT_MONITORCHANGED    0x012C
+
+/* TS_MM_DATA_SAMPLE.SampleExtensions */
+#define TSMM_SAMPLE_EXT_CLEANPOINT          0x00000001
+#define TSMM_SAMPLE_EXT_DISCONTINUITY       0x00000002
+#define TSMM_SAMPLE_EXT_INTERLACED          0x00000004
+#define TSMM_SAMPLE_EXT_BOTTOMFIELDFIRST    0x00000008
+#define TSMM_SAMPLE_EXT_REPEATFIELDFIRST    0x00000010
+#define TSMM_SAMPLE_EXT_SINGLEFIELD         0x00000020
+#define TSMM_SAMPLE_EXT_DERIVEDFROMTOPFIELD 0x00000040
+#define TSMM_SAMPLE_EXT_HAS_NO_TIMESTAMPS   0x00000080
+#define TSMM_SAMPLE_EXT_RELATIVE_TIMESTAMPS 0x00000100
+#define TSMM_SAMPLE_EXT_ABSOLUTE_TIMESTAMPS 0x00000200
+
+/* MajorType */
+#define TSMF_MAJOR_TYPE_UNKNOWN             0
+#define TSMF_MAJOR_TYPE_VIDEO               1
+#define TSMF_MAJOR_TYPE_AUDIO               2
+
+/* SubType */
+#define TSMF_SUB_TYPE_UNKNOWN               0
+#define TSMF_SUB_TYPE_WVC1                  1
+#define TSMF_SUB_TYPE_WMA2                  2
+#define TSMF_SUB_TYPE_WMA9                  3
+#define TSMF_SUB_TYPE_MP3                   4
+#define TSMF_SUB_TYPE_MP2A                  5
+#define TSMF_SUB_TYPE_MP2V                  6
+#define TSMF_SUB_TYPE_WMV3                  7
+#define TSMF_SUB_TYPE_AAC                   8
+#define TSMF_SUB_TYPE_H264                  9
+#define TSMF_SUB_TYPE_AVC1                 10
+#define TSMF_SUB_TYPE_AC3                  11
+
+/* FormatType */
+#define TSMF_FORMAT_TYPE_UNKNOWN            0
+#define TSMF_FORMAT_TYPE_MFVIDEOFORMAT      1
+#define TSMF_FORMAT_TYPE_WAVEFORMATEX       2
+#define TSMF_FORMAT_TYPE_MPEG2VIDEOINFO     3
+#define TSMF_FORMAT_TYPE_VIDEOINFO2         4
+
+#endif
+
diff --git a/channels/drdynvc/tsmf/tsmf_decoder.c b/channels/drdynvc/tsmf/tsmf_decoder.c
new file mode 100644 (file)
index 0000000..db31c02
--- /dev/null
@@ -0,0 +1,81 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Video Redirection Virtual Channel - Decoder
+ *
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <freerdp/utils/memory.h>
+#include <freerdp/utils/load_plugin.h>
+
+#include "drdynvc_types.h"
+#include "tsmf_types.h"
+#include "tsmf_constants.h"
+#include "tsmf_decoder.h"
+
+static ITSMFDecoder* tsmf_load_decoder_by_name(const char* name, TS_AM_MEDIA_TYPE* media_type)
+{
+       ITSMFDecoder* decoder;
+       TSMF_DECODER_ENTRY entry;
+       char* fullname;
+
+       if (strrchr(name, '.') != NULL)
+               entry = (TSMF_DECODER_ENTRY) freerdp_load_plugin(name, TSMF_DECODER_EXPORT_FUNC_NAME);
+       else
+       {
+               fullname = xzalloc(strlen(name) + 6);
+               strcpy(fullname, "tsmf_");
+               strcat(fullname, name);
+               entry = (TSMF_DECODER_ENTRY) freerdp_load_plugin(fullname, TSMF_DECODER_EXPORT_FUNC_NAME);
+               xfree(fullname);
+       }
+       if (entry == NULL)
+       {
+               return NULL;
+       }
+
+       decoder = entry();
+       if (decoder == NULL)
+       {
+               DEBUG_WARN("failed to call export function in %s", name);
+               return NULL;
+       }
+       if (!decoder->SetFormat(decoder, media_type))
+       {
+               decoder->Free(decoder);
+               decoder = NULL;
+       }
+       return decoder;
+}
+
+ITSMFDecoder* tsmf_load_decoder(const char* name, TS_AM_MEDIA_TYPE* media_type)
+{
+       ITSMFDecoder* decoder;
+
+       if (name)
+       {
+               decoder = tsmf_load_decoder_by_name(name, media_type);
+       }
+       else
+       {
+               decoder = tsmf_load_decoder_by_name("ffmpeg", media_type);
+       }
+
+       return decoder;
+}
+
diff --git a/channels/drdynvc/tsmf/tsmf_decoder.h b/channels/drdynvc/tsmf/tsmf_decoder.h
new file mode 100644 (file)
index 0000000..2aee84f
--- /dev/null
@@ -0,0 +1,50 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Video Redirection Virtual Channel - Decoder
+ *
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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 __TSMF_DECODER_H
+#define __TSMF_DECODER_H
+
+#include "drdynvc_types.h"
+#include "tsmf_types.h"
+
+typedef struct _ITSMFDecoder ITSMFDecoder;
+
+struct _ITSMFDecoder
+{
+       /* Set the decoder format. Return true if supported. */
+       boolean (*SetFormat) (ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* media_type);
+       /* Decode a sample. */
+       boolean (*Decode) (ITSMFDecoder* decoder, const uint8* data, uint32 data_size, uint32 extensions);
+       /* Get the decoded data */
+       uint8* (*GetDecodedData) (ITSMFDecoder* decoder, uint32* size);
+       /* Get the pixel format of decoded video frame */
+       uint32 (*GetDecodedFormat) (ITSMFDecoder* decoder);
+       /* Get the width and height of decoded video frame */
+       boolean (*GetDecodedDimension) (ITSMFDecoder* decoder, uint32* width, uint32* height);
+       /* Free the decoder */
+       void (*Free) (ITSMFDecoder* decoder);
+};
+
+#define TSMF_DECODER_EXPORT_FUNC_NAME "TSMFDecoderEntry"
+typedef ITSMFDecoder* (*TSMF_DECODER_ENTRY) (void);
+
+ITSMFDecoder* tsmf_load_decoder(const char* name, TS_AM_MEDIA_TYPE* media_type);
+
+#endif
+
diff --git a/channels/drdynvc/tsmf/tsmf_ifman.c b/channels/drdynvc/tsmf/tsmf_ifman.c
new file mode 100644 (file)
index 0000000..10d351d
--- /dev/null
@@ -0,0 +1,478 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Video Redirection Virtual Channel - Interface Manipulation
+ *
+ * Copyright 2010-2011 Vic Lee
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <freerdp/utils/memory.h>
+#include <freerdp/utils/stream.h>
+
+#include "drdynvc_types.h"
+#include "tsmf_constants.h"
+#include "tsmf_media.h"
+#include "tsmf_codec.h"
+
+#include "tsmf_ifman.h"
+
+int tsmf_ifman_rim_exchange_capability_request(TSMF_IFMAN* ifman)
+{
+       uint32 CapabilityValue;
+
+       stream_read_uint32(ifman->input, CapabilityValue);
+       DEBUG_DVC("server CapabilityValue %d", CapabilityValue);
+
+       stream_check_size(ifman->output, 8);
+       stream_write_uint32(ifman->output, 1); /* CapabilityValue */
+       stream_write_uint32(ifman->output, 0); /* Result */
+
+       return 0;
+}
+
+int tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman)
+{
+       uint32 i;
+       uint32 v;
+       uint32 pos;
+       uint32 CapabilityType;
+       uint32 cbCapabilityLength;
+       uint32 numHostCapabilities;
+
+       pos = stream_get_pos(ifman->output);
+       stream_check_size(ifman->output, ifman->input_size + 4);
+       stream_copy(ifman->output, ifman->input, ifman->input_size);
+
+       stream_set_pos(ifman->output, pos);
+       stream_read_uint32(ifman->output, numHostCapabilities);
+       for (i = 0; i < numHostCapabilities; i++)
+       {
+               stream_read_uint32(ifman->output, CapabilityType);
+               stream_read_uint32(ifman->output, cbCapabilityLength);
+               pos = stream_get_pos(ifman->output);
+               switch (CapabilityType)
+               {
+                       case 1: /* Protocol version request */
+                               stream_read_uint32(ifman->output, v);
+                               DEBUG_DVC("server protocol version %d", v);
+                               break;
+                       case 2: /* Supported platform */
+                               stream_peek_uint32(ifman->output, v);
+                               DEBUG_DVC("server supported platform %d", v);
+                               /* Claim that we support both MF and DShow platforms. */
+                               stream_write_uint32(ifman->output,
+                                       MMREDIR_CAPABILITY_PLATFORM_MF | MMREDIR_CAPABILITY_PLATFORM_DSHOW);
+                               break;
+                       default:
+                               DEBUG_WARN("unknown capability type %d", CapabilityType);
+                               break;
+               }
+               stream_set_pos(ifman->output, pos + cbCapabilityLength);
+       }
+       stream_write_uint32(ifman->output, 0); /* Result */
+
+       ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
+
+       return 0;
+}
+
+int tsmf_ifman_check_format_support_request(TSMF_IFMAN* ifman)
+{
+       uint32 numMediaType;
+       uint32 PlatformCookie;
+       uint32 FormatSupported = 1;
+
+       stream_read_uint32(ifman->input, PlatformCookie);
+       stream_seek_uint32(ifman->input); /* NoRolloverFlags (4 bytes) */
+       stream_read_uint32(ifman->input, numMediaType);
+
+       DEBUG_DVC("PlatformCookie %d numMediaType %d", PlatformCookie, numMediaType);
+
+       if (!tsmf_codec_check_media_type(ifman->input))
+               FormatSupported = 0;
+
+       if (FormatSupported)
+               DEBUG_DVC("format ok.");
+
+       stream_check_size(ifman->output, 12);
+       stream_write_uint32(ifman->output, FormatSupported);
+       stream_write_uint32(ifman->output, PlatformCookie);
+       stream_write_uint32(ifman->output, 0); /* Result */
+
+       ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
+
+       return 0;
+}
+
+int tsmf_ifman_on_new_presentation(TSMF_IFMAN* ifman)
+{
+       int error = 0;
+       TSMF_PRESENTATION* presentation;
+
+       DEBUG_DVC("");
+
+       presentation = tsmf_presentation_new(stream_get_tail(ifman->input), ifman->channel_callback);
+       if (presentation == NULL)
+               error = 1;
+       tsmf_presentation_set_audio_device(presentation, ifman->audio_name, ifman->audio_device);
+       ifman->output_pending = true;
+       return error;
+}
+
+int tsmf_ifman_add_stream(TSMF_IFMAN* ifman)
+{
+       uint32 StreamId;
+       int error = 0;
+       TSMF_STREAM* stream;
+       TSMF_PRESENTATION* presentation;
+
+       DEBUG_DVC("");
+
+       presentation = tsmf_presentation_find_by_id(stream_get_tail(ifman->input));
+       stream_seek(ifman->input, 16);
+
+       if (presentation == NULL)
+               error = 1;
+       else
+       {
+               stream_read_uint32(ifman->input, StreamId);
+               stream_seek_uint32(ifman->input); /* numMediaType */
+               stream = tsmf_stream_new(presentation, StreamId);
+               if (stream)
+                       tsmf_stream_set_format(stream, ifman->decoder_name, ifman->input);
+       }