You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by jm...@apache.org on 2016/06/02 18:45:08 UTC

[01/26] incubator-guacamole-server git commit: GUACAMOLE-25: Implement buffer attachment in Stream_New() and Stream_Free() compatibility functions.

Repository: incubator-guacamole-server
Updated Branches:
  refs/heads/master ec93a2989 -> 995b6d669


GUACAMOLE-25: Implement buffer attachment in Stream_New() and Stream_Free() compatibility functions.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/f1d4393e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/f1d4393e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/f1d4393e

Branch: refs/heads/master
Commit: f1d4393eb8cedeec0214c497c73a528806ae2118
Parents: 1393358
Author: Michael Jumper <mj...@apache.org>
Authored: Mon May 9 22:18:49 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 13:50:28 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/compat/winpr-stream.c | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/f1d4393e/src/protocols/rdp/compat/winpr-stream.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/compat/winpr-stream.c b/src/protocols/rdp/compat/winpr-stream.c
index 528177d..8be4546 100644
--- a/src/protocols/rdp/compat/winpr-stream.c
+++ b/src/protocols/rdp/compat/winpr-stream.c
@@ -22,17 +22,26 @@
 #include "winpr-stream.h"
 #include "winpr-wtypes.h"
 
-/*
- * NOTE: Because the old API did not support local allocation of the buffer
- *       for each stream, these compatibility implementations ignore
- *       the parameters of Stream_New() and Stream_Free() that provide them.
- */
-
 wStream* Stream_New(BYTE* buffer, size_t size) {
-    return stream_new(size);
+
+    /* If no buffer is provided, allocate a new stream of the given size */
+    if (buffer == NULL)
+       return stream_new(size);
+
+    /* Otherwise allocate an empty stream and assign the given buffer */
+    wStream* stream = stream_new(0);
+    stream_attach(stream, buffer, size);
+    return stream;
+
 }
 
 void Stream_Free(wStream* s, BOOL bFreeBuffer) {
+
+    /* Disassociate buffer if it will be freed externally */
+    if (!bFreeBuffer)
+        stream_detach(s);
+
     stream_free(s);
+
 }
 


[16/26] incubator-guacamole-server git commit: GUACAMOLE-25: Partially handle the Open PDU.

Posted by jm...@apache.org.
GUACAMOLE-25: Partially handle the Open PDU.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/63cd2ce5
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/63cd2ce5
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/63cd2ce5

Branch: refs/heads/master
Commit: 63cd2ce512a92a31f497d09d5e1903aeab57fd8f
Parents: 86806a3
Author: Michael Jumper <mj...@apache.org>
Authored: Sun Apr 17 02:36:32 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 13:50:28 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/guac_ai/ai_messages.c | 82 +++++++++++++++++++++++++---
 1 file changed, 74 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/63cd2ce5/src/protocols/rdp/guac_ai/ai_messages.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/guac_ai/ai_messages.c b/src/protocols/rdp/guac_ai/ai_messages.c
index d4cc28d..8b2d0d7 100644
--- a/src/protocols/rdp/guac_ai/ai_messages.c
+++ b/src/protocols/rdp/guac_ai/ai_messages.c
@@ -101,14 +101,14 @@ static void guac_rdp_ai_write_format(wStream* stream,
  */
 static void guac_rdp_ai_send_incoming_data(IWTSVirtualChannel* channel) {
 
-    /* Build response version PDU */
-    wStream* response = Stream_New(NULL, 1);
-    Stream_Write_UINT8(response, GUAC_RDP_MSG_SNDIN_DATA_INCOMING); /* MessageId */
+    /* Build data incoming PDU */
+    wStream* stream = Stream_New(NULL, 1);
+    Stream_Write_UINT8(stream, GUAC_RDP_MSG_SNDIN_DATA_INCOMING); /* MessageId */
 
-    /* Send response */
-    channel->Write(channel, (UINT32) Stream_GetPosition(response),
-            Stream_Buffer(response), NULL);
-    Stream_Free(response, TRUE);
+    /* Send stream */
+    channel->Write(channel, (UINT32) Stream_GetPosition(stream),
+            Stream_Buffer(stream), NULL);
+    Stream_Free(stream, TRUE);
 
 }
 
@@ -155,6 +155,60 @@ static void guac_rdp_ai_send_formats(IWTSVirtualChannel* channel,
 
 }
 
+/**
+ * Sends an Open Reply PDU along the given channel. An Open Reply PDU is
+ * used by the client to acknowledge the successful opening of the AUDIO_INPUT
+ * channel.
+ *
+ * @param channel
+ *     The channel along which the PDU should be sent.
+ *
+ * @param result
+ *     The HRESULT code to send to the server indicating success, failure, etc.
+ */
+static void guac_rdp_ai_send_open_reply(IWTSVirtualChannel* channel,
+        UINT32 result) {
+
+    /* Build open reply PDU */
+    wStream* stream = Stream_New(NULL, 5);
+    Stream_Write_UINT8(stream, GUAC_RDP_MSG_SNDIN_OPEN_REPLY); /* MessageId */
+    Stream_Write_UINT32(stream, result); /* Result */
+
+    /* Send stream */
+    channel->Write(channel, (UINT32) Stream_GetPosition(stream),
+            Stream_Buffer(stream), NULL);
+    Stream_Free(stream, TRUE);
+
+}
+
+/**
+ * Sends a Format Change PDU along the given channel. A Format Change PDU is
+ * used by the client to acknowledge the format being used for data sent
+ * along the AUDIO_INPUT channel.
+ *
+ * @param channel
+ *     The channel along which the PDU should be sent.
+ *
+ * @param format
+ *     The index of the format being acknowledged, which must be the index of
+ *     the format within the original Sound Formats PDU received from the
+ *     server.
+ */
+static void guac_rdp_ai_send_formatchange(IWTSVirtualChannel* channel,
+        UINT32 format) {
+
+    /* Build format change PDU */
+    wStream* stream = Stream_New(NULL, 5);
+    Stream_Write_UINT8(stream, GUAC_RDP_MSG_SNDIN_FORMATCHANGE); /* MessageId */
+    Stream_Write_UINT32(stream, format); /* NewFormat */
+
+    /* Send stream */
+    channel->Write(channel, (UINT32) Stream_GetPosition(stream),
+            Stream_Buffer(stream), NULL);
+    Stream_Free(stream, TRUE);
+
+}
+
 void guac_rdp_ai_process_version(guac_client* client,
         IWTSVirtualChannel* channel, wStream* stream) {
 
@@ -212,8 +266,20 @@ void guac_rdp_ai_process_formats(guac_client* client,
 void guac_rdp_ai_process_open(guac_client* client,
         IWTSVirtualChannel* channel, wStream* stream) {
 
+    UINT32 packet_frames;
+    UINT32 initial_format;
+
+    Stream_Read_UINT32(stream, packet_frames); /* FramesPerPacket */
+    Stream_Read_UINT32(stream, initial_format); /* InitialFormat */
+
     /* STUB */
-    guac_client_log(client, GUAC_LOG_DEBUG, "AUDIO_INPUT: open");
+    guac_client_log(client, GUAC_LOG_DEBUG, "AUDIO_INPUT: open: "
+            "packet_frames=%i, initial_format=%i",
+            packet_frames, initial_format);
+
+    /* Success */
+    guac_rdp_ai_send_formatchange(channel, initial_format);
+    guac_rdp_ai_send_open_reply(channel, 0);
 
 }
 


[25/26] incubator-guacamole-server git commit: GUACAMOLE-25: Update documentation regarding loading of dynamic virtual channel plugins.

Posted by jm...@apache.org.
GUACAMOLE-25: Update documentation regarding loading of dynamic virtual channel plugins.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/402b0393
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/402b0393
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/402b0393

Branch: refs/heads/master
Commit: 402b0393844fb2d6180ccaed341108b349404c83
Parents: 0d29694
Author: Michael Jumper <mj...@apache.org>
Authored: Wed Jun 1 22:06:17 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Jun 1 22:06:17 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/audio_input.h | 12 +++++++++---
 src/protocols/rdp/rdp_disp.h    | 20 ++++++++++++++++----
 2 files changed, 25 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/402b0393/src/protocols/rdp/audio_input.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.h b/src/protocols/rdp/audio_input.h
index bd84fe1..6280662 100644
--- a/src/protocols/rdp/audio_input.h
+++ b/src/protocols/rdp/audio_input.h
@@ -294,12 +294,18 @@ guac_user_blob_handler guac_rdp_audio_blob_handler;
 guac_user_end_handler guac_rdp_audio_end_handler;
 
 /**
- * Loads Guacamole's "guacai" plugin for FreeRDP, adding support for the
- * "AUDIO_INPUT" dynamic virtual channel. This function must ONLY be called
- * after FreeRDP's "drdynvc" virtual channel plugin has been loaded.
+ * Adds Guacamole's "guacai" plugin to the list of dynamic virtual channel
+ * plugins to be loaded by FreeRDP's "drdynvc" plugin. The plugin will only
+ * be loaded once guac_rdp_load_drdynvc() is invoked with the guac_rdp_dvc_list
+ * passed to this function. The "guacai" plugin ultimately adds support for the
+ * "AUDIO_INPUT"  dynamic virtual channel.
  *
  * @param context
  *     The rdpContext associated with the active RDP session.
+ *
+ * @param list
+ *     The guac_rdp_dvc_list to which the "guacai" plugin should be added, such
+ *     that it may later be loaded by guac_rdp_load_drdynvc().
  */
 void guac_rdp_audio_load_plugin(rdpContext* context, guac_rdp_dvc_list* list);
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/402b0393/src/protocols/rdp/rdp_disp.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/rdp_disp.h b/src/protocols/rdp/rdp_disp.h
index 093e7ed..0f34fe1 100644
--- a/src/protocols/rdp/rdp_disp.h
+++ b/src/protocols/rdp/rdp_disp.h
@@ -97,12 +97,24 @@ guac_rdp_disp* guac_rdp_disp_alloc();
 void guac_rdp_disp_free(guac_rdp_disp* disp);
 
 /**
- * Loads the "disp" plugin for FreeRDP. It is still up to external code to
- * detect when the "disp" channel is connected, and update the guac_rdp_disp
- * with a call to guac_rdp_disp_connect().
- *
  * @param context The rdpContext associated with the active RDP session.
  */
+/**
+ * Adds FreeRDP's "disp" plugin to the list of dynamic virtual channel plugins
+ * to be loaded by FreeRDP's "drdynvc" plugin. The plugin will only be loaded
+ * once guac_rdp_load_drdynvc() is invoked with the guac_rdp_dvc_list passed to
+ * this function. The "disp" plugin ultimately adds support for the Display
+ * Update channel. NOTE: It is still up to external code to detect when the
+ * "disp" channel is connected, and update the guac_rdp_disp with a call to
+ * guac_rdp_disp_connect().
+ *
+ * @param context
+ *     The rdpContext associated with the active RDP session.
+ *
+ * @param list
+ *     The guac_rdp_dvc_list to which the "disp" plugin should be added, such
+ *     that it may later be loaded by guac_rdp_load_drdynvc().
+ */
 void guac_rdp_disp_load_plugin(rdpContext* context, guac_rdp_dvc_list* list);
 
 #ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT


[20/26] incubator-guacamole-server git commit: GUACAMOLE-25: Remove STUB.

Posted by jm...@apache.org.
GUACAMOLE-25: Remove STUB.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/260d0cd3
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/260d0cd3
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/260d0cd3

Branch: refs/heads/master
Commit: 260d0cd340f78c91dd29acd6de97bf57f2e46cc9
Parents: 533a47f
Author: Michael Jumper <mj...@apache.org>
Authored: Wed May 11 14:09:48 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 13:50:29 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/guac_ai/ai_messages.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/260d0cd3/src/protocols/rdp/guac_ai/ai_messages.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/guac_ai/ai_messages.c b/src/protocols/rdp/guac_ai/ai_messages.c
index 520416c..eeb3e28 100644
--- a/src/protocols/rdp/guac_ai/ai_messages.c
+++ b/src/protocols/rdp/guac_ai/ai_messages.c
@@ -319,8 +319,10 @@ void guac_rdp_ai_process_open(guac_client* client,
 void guac_rdp_ai_process_formatchange(guac_client* client,
         IWTSVirtualChannel* channel, wStream* stream) {
 
-    /* STUB: Should not be called as we only accept one format */
-    guac_client_log(client, GUAC_LOG_DEBUG, "AUDIO_INPUT: formatchange");
+    /* Should not be called as we only accept one format */
+    guac_client_log(client, GUAC_LOG_DEBUG,
+            "RDP server requesting AUDIO_INPUT format change despite only one "
+            "format available.");
 
 }
 


[14/26] incubator-guacamole-server git commit: GUACAMOLE-25: Add support for multiple versions of IWTSVirtualChannelCallback.

Posted by jm...@apache.org.
GUACAMOLE-25: Add support for multiple versions of IWTSVirtualChannelCallback.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/10883323
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/10883323
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/10883323

Branch: refs/heads/master
Commit: 1088332376343c52ca6c66fbd2053146e5b72d22
Parents: ac94fd4
Author: Michael Jumper <mj...@apache.org>
Authored: Sat Apr 16 23:28:50 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 13:50:28 2016 -0700

----------------------------------------------------------------------
 configure.ac                           | 22 ++++++++++++++++++++++
 src/protocols/rdp/guac_ai/ai_service.c | 29 +++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/10883323/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 485c10d..04cb6bb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -765,6 +765,28 @@ then
 fi
 
 #
+# FreeRDP: IWTSVirtualChannelCallback
+#
+
+if test "x${have_freerdp}" = "xyes"
+then
+    AC_MSG_CHECKING([whether IWTSVirtualChannelCallback.OnDataReceived() uses a wStream])
+    AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#include <winpr/wtypes.h>
+                                        #include <freerdp/dvc.h>
+                                        #include <freerdp/freerdp.h>
+                                        int __data_received(
+                                            IWTSVirtualChannelCallback* channel_callback,
+                                            wStream* stream);
+                                        IWTSVirtualChannelCallback cb = {
+                                            .OnDataReceived = __data_received
+                                        };]])],
+                      [AC_MSG_RESULT([yes])],
+                      [AC_MSG_RESULT([no])
+                       AC_DEFINE([LEGACY_IWTSVIRTUALCHANNELCALLBACK],,
+                                 [Whether the legacy IWTSVirtualChannelCallback API was found])])
+fi
+
+#
 # FreeRDP: Decompression function variants
 #
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/10883323/src/protocols/rdp/guac_ai/ai_service.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/guac_ai/ai_service.c b/src/protocols/rdp/guac_ai/ai_service.c
index 5b72354..e822f90 100644
--- a/src/protocols/rdp/guac_ai/ai_service.c
+++ b/src/protocols/rdp/guac_ai/ai_service.c
@@ -62,6 +62,7 @@ static void guac_rdp_ai_handle_data(guac_client* client, wStream* stream) {
 
 }
 
+#if LEGACY_IWTSVIRTUALCHANNELCALLBACK
 /**
  * Callback which is invoked when data is received along a connection to the
  * AUDIO_INPUT plugin. This callback is specific to FreeRDP 1.1 and older.
@@ -93,6 +94,34 @@ static int guac_rdp_ai_data(IWTSVirtualChannelCallback* channel_callback,
     return 0;
 
 }
+#else
+/**
+ * Callback which is invoked when data is received along a connection to the
+ * AUDIO_INPUT plugin. This callback is specific to FreeRDP 1.2 and newer.
+ *
+ * @param channel_callback
+ *     The IWTSVirtualChannelCallback structure to which this callback was
+ *     originally assigned.
+ *
+ * @param stream
+ *     The data received.
+ *
+ * @return
+ *     Always zero.
+ */
+static int guac_rdp_ai_data(IWTSVirtualChannelCallback* channel_callback,
+        wStream* stream) {
+
+    guac_rdp_ai_channel_callback* ai_channel_callback =
+        (guac_rdp_ai_channel_callback*) channel_callback;
+
+    /* Invoke generalized (API-independent) data handler */
+    guac_rdp_ai_handle_data(ai_channel_callback->client, stream);
+
+    return 0;
+
+}
+#endif
 
 /**
  * Callback which is invoked when a connection to the AUDIO_INPUT plugin is


[21/26] incubator-guacamole-server git commit: GUACAMOLE-25: Store audio format within common structure.

Posted by jm...@apache.org.
GUACAMOLE-25: Store audio format within common structure.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/ad00cce0
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/ad00cce0
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/ad00cce0

Branch: refs/heads/master
Commit: ad00cce0ad882e8e549c74212cf33826ea44c4e1
Parents: 260d0cd
Author: Michael Jumper <mj...@apache.org>
Authored: Wed May 25 14:38:22 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 14:38:22 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/audio_input.c | 12 +++----
 src/protocols/rdp/audio_input.h | 62 +++++++++++++++++-------------------
 2 files changed, 36 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/ad00cce0/src/protocols/rdp/audio_input.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.c b/src/protocols/rdp/audio_input.c
index b2f61bd..9e88fb5 100644
--- a/src/protocols/rdp/audio_input.c
+++ b/src/protocols/rdp/audio_input.c
@@ -242,9 +242,9 @@ void guac_rdp_audio_buffer_set_stream(guac_rdp_audio_buffer* audio_buffer,
     /* Associate received stream */
     audio_buffer->user = user;
     audio_buffer->stream = stream;
-    audio_buffer->in_rate = rate;
-    audio_buffer->in_channels = channels;
-    audio_buffer->in_bps = bps;
+    audio_buffer->in_format.rate = rate;
+    audio_buffer->in_format.channels = channels;
+    audio_buffer->in_format.bps = bps;
 
     /* Acknowledge stream creation (if buffer is ready to receive) */
     guac_rdp_audio_buffer_ack(audio_buffer,
@@ -262,9 +262,9 @@ void guac_rdp_audio_buffer_begin(guac_rdp_audio_buffer* audio_buffer,
 
     /* Reset buffer state to provided values */
     audio_buffer->bytes_written = 0;
-    audio_buffer->out_rate = rate;
-    audio_buffer->out_channels = channels;
-    audio_buffer->out_bps = bps;
+    audio_buffer->out_format.rate = rate;
+    audio_buffer->out_format.channels = channels;
+    audio_buffer->out_format.bps = bps;
     audio_buffer->packet_size = packet_size;
     audio_buffer->flush_handler = flush_handler;
     audio_buffer->data = data;

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/ad00cce0/src/protocols/rdp/audio_input.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.h b/src/protocols/rdp/audio_input.h
index 2514b50..0970671 100644
--- a/src/protocols/rdp/audio_input.h
+++ b/src/protocols/rdp/audio_input.h
@@ -49,6 +49,29 @@ typedef void guac_rdp_audio_buffer_flush_handler(char* buffer, int length,
         void* data);
 
 /**
+ * A description of an arbitrary PCM audio format.
+ */
+typedef struct guac_rdp_audio_format {
+
+    /**
+     * The rate of the audio data in samples per second.
+     */
+    int rate;
+
+    /**
+     * The number of channels included in the audio data. This will be 1 for
+     * monaural audio and 2 for stereo.
+     */
+    int channels;
+
+    /**
+     * The size of each sample within the audio data, in bytes.
+     */
+    int bps;
+
+} guac_rdp_audio_format;
+
+/**
  * A buffer of arbitrary audio data. Received audio data can be written to this
  * buffer, and will automatically be flushed via a given handler once the
  * internal buffer reaches capacity.
@@ -74,43 +97,18 @@ typedef struct guac_rdp_audio_buffer {
     guac_stream* stream;
 
     /**
-     * The rate of the audio stream being received from the user, if any, in
-     * samples per second. If no stream is yet associated, this value is
+     * The PCM format of the audio stream being received from the user, if any.
+     * If no stream is yet associated, the values stored within this format are
      * undefined.
      */
-    int in_rate;
-
-    /**
-     * The number of channels included in the audio stream being received from
-     * the user, if any. If no stream is yet associated, this value is
-     * undefined.
-     */
-    int in_channels;
-
-    /**
-     * The size of each sample within the audio stream being received from the
-     * user, if any, in bytes. If no stream is yet associated, this value is
-     * undefined.
-     */
-    int in_bps;
-
-    /**
-     * The rate of the audio stream expected by RDP, if any, in samples per
-     * second. If no stream is yet associated, this value is undefined.
-     */
-    int out_rate;
-
-    /**
-     * The number of channels included in the audio stream expected by RDP, if
-     * any. If no stream is yet associated, this value is undefined.
-     */
-    int out_channels;
+    guac_rdp_audio_format in_format;
 
     /**
-     * The size of each sample within the audio stream expected by RDP, if any,
-     * in bytes. If no stream is yet associated, this value is undefined.
+     * The PCM format of the audio stream expected by RDP, if any. If no audio
+     * stream has yet been requested by the RDP server, the values stored
+     * within this format are undefined.
      */
-    int out_bps;
+    guac_rdp_audio_format out_format;
 
     /**
      * The size that each audio packet must be, in bytes. The packet buffer


[10/26] incubator-guacamole-server git commit: GUACAMOLE-25: Handle the server's Sound Formats PDU.

Posted by jm...@apache.org.
GUACAMOLE-25: Handle the server's Sound Formats PDU.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/86806a37
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/86806a37
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/86806a37

Branch: refs/heads/master
Commit: 86806a37592624707aaa7450f6b4fe06bb1cf469
Parents: 503ffb0
Author: Michael Jumper <mj...@apache.org>
Authored: Sun Apr 17 02:11:29 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 13:50:28 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/guac_ai/ai_messages.c | 147 ++++++++++++++++++++++++++-
 src/protocols/rdp/guac_ai/ai_messages.h |  59 +++++++++++
 2 files changed, 204 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/86806a37/src/protocols/rdp/guac_ai/ai_messages.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/guac_ai/ai_messages.c b/src/protocols/rdp/guac_ai/ai_messages.c
index c799a44..d4cc28d 100644
--- a/src/protocols/rdp/guac_ai/ai_messages.c
+++ b/src/protocols/rdp/guac_ai/ai_messages.c
@@ -35,6 +35,126 @@
 #include "compat/winpr-stream.h"
 #endif
 
+/**
+ * Reads AUDIO_FORMAT data from the given stream into the given struct.
+ *
+ * @param stream
+ *     The stream to read AUDIO_FORMAT data from.
+ *
+ * @param format
+ *     The structure to populate with data from the stream.
+ */
+static void guac_rdp_ai_read_format(wStream* stream,
+        guac_rdp_ai_format* format) {
+
+    /* Read audio format into structure */
+    Stream_Read_UINT16(stream, format->tag); /* wFormatTag */
+    Stream_Read_UINT16(stream, format->channels); /* nChannels */
+    Stream_Read_UINT32(stream, format->rate); /* nSamplesPerSec */
+    Stream_Read_UINT32(stream, format->bytes_per_sec); /* nAvgBytesPerSec */
+    Stream_Read_UINT16(stream, format->block_align); /* nBlockAlign */
+    Stream_Read_UINT16(stream, format->bps); /* wBitsPerSample */
+    Stream_Read_UINT16(stream, format->data_size); /* cbSize */
+
+    /* Read arbitrary data block (if applicable) */
+    if (format->data_size != 0) {
+        format->data = Stream_Pointer(stream); /* data */
+        Stream_Seek(stream, format->data_size);
+    }
+
+}
+
+/**
+ * Writes AUDIO_FORMAT data to the given stream from the given struct.
+ *
+ * @param stream
+ *     The stream to write AUDIO_FORMAT data to.
+ *
+ * @param format
+ *     The structure containing the data that should be written to the stream.
+ */
+static void guac_rdp_ai_write_format(wStream* stream,
+        guac_rdp_ai_format* format) {
+
+    /* Write audio format into structure */
+    Stream_Write_UINT16(stream, format->tag); /* wFormatTag */
+    Stream_Write_UINT16(stream, format->channels); /* nChannels */
+    Stream_Write_UINT32(stream, format->rate); /* nSamplesPerSec */
+    Stream_Write_UINT32(stream, format->bytes_per_sec); /* nAvgBytesPerSec */
+    Stream_Write_UINT16(stream, format->block_align); /* nBlockAlign */
+    Stream_Write_UINT16(stream, format->bps); /* wBitsPerSample */
+    Stream_Write_UINT16(stream, format->data_size); /* cbSize */
+
+    /* Write arbitrary data block (if applicable) */
+    if (format->data_size != 0)
+        Stream_Write(stream, format->data, format->data_size);
+
+}
+
+/**
+ * Sends a Data Incoming PDU along the given channel. A Data Incoming PDU is
+ * used by the client to indicate to the server that format or audio data is
+ * about to be sent.
+ *
+ * @param channel
+ *     The channel along which the PDU should be sent.
+ */
+static void guac_rdp_ai_send_incoming_data(IWTSVirtualChannel* channel) {
+
+    /* Build response version PDU */
+    wStream* response = Stream_New(NULL, 1);
+    Stream_Write_UINT8(response, GUAC_RDP_MSG_SNDIN_DATA_INCOMING); /* MessageId */
+
+    /* Send response */
+    channel->Write(channel, (UINT32) Stream_GetPosition(response),
+            Stream_Buffer(response), NULL);
+    Stream_Free(response, TRUE);
+
+}
+
+/**
+ * Sends a Sound Formats PDU along the given channel. A Sound Formats PDU is
+ * used by the client to indicate to the server which formats of audio it
+ * supports (in response to the server sending exactly the same type of PDU).
+ * This PDU MUST be preceded by the Data Incoming PDU.
+ *
+ * @param channel
+ *     The channel along which the PDU should be sent.
+ *
+ * @param formats
+ *     An array of all supported formats.
+ *
+ * @param num_formats
+ *     The number of entries in the formats array.
+ */
+static void guac_rdp_ai_send_formats(IWTSVirtualChannel* channel,
+        guac_rdp_ai_format* formats, int num_formats) {
+
+    int index;
+    int packet_size = 9;
+
+    /* Calculate packet size */
+    for (index = 0; index < num_formats; index++)
+        packet_size += 18 + formats[index].data_size;
+
+    wStream* stream = Stream_New(NULL, packet_size);
+
+    /* Write header */
+    Stream_Write_UINT8(stream, GUAC_RDP_MSG_SNDIN_FORMATS); /* MessageId */
+    Stream_Write_UINT32(stream, num_formats); /* NumFormats */
+    Stream_Write_UINT32(stream, packet_size); /* cbSizeFormatsPacket  */
+
+    /* Write all formats */
+    for (index = 0; index < num_formats; index++)
+        guac_rdp_ai_write_format(stream, &(formats[index]));
+
+    /* Send PDU */
+    channel->Write(channel, (UINT32) Stream_GetPosition(stream),
+            Stream_Buffer(stream), NULL);
+    Stream_Free(stream, TRUE);
+
+}
+
 void guac_rdp_ai_process_version(guac_client* client,
         IWTSVirtualChannel* channel, wStream* stream) {
 
@@ -61,8 +181,31 @@ void guac_rdp_ai_process_version(guac_client* client,
 void guac_rdp_ai_process_formats(guac_client* client,
         IWTSVirtualChannel* channel, wStream* stream) {
 
-    /* STUB */
-    guac_client_log(client, GUAC_LOG_DEBUG, "AUDIO_INPUT: formats");
+    UINT32 num_formats;
+    Stream_Read_UINT32(stream, num_formats); /* NumFormats */
+    Stream_Seek_UINT32(stream); /* cbSizeFormatsPacket (MUST BE IGNORED) */
+
+    UINT32 index;
+    for (index = 0; index < num_formats; index++) {
+
+        guac_rdp_ai_format format;
+        guac_rdp_ai_read_format(stream, &format);
+
+        /* Ignore anything but WAVE_FORMAT_PCM */
+        if (format.tag != GUAC_RDP_WAVE_FORMAT_PCM)
+            continue;
+
+        /* Accept single format */
+        guac_rdp_ai_send_incoming_data(channel);
+        guac_rdp_ai_send_formats(channel, &format, 1);
+        return;
+
+    }
+
+    /* No formats available */
+    guac_client_log(client, GUAC_LOG_WARNING, "AUDIO_INPUT: No WAVE format.");
+    guac_rdp_ai_send_incoming_data(channel);
+    guac_rdp_ai_send_formats(channel, NULL, 0);
 
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/86806a37/src/protocols/rdp/guac_ai/ai_messages.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/guac_ai/ai_messages.h b/src/protocols/rdp/guac_ai/ai_messages.h
index 96282e5..55cf6e9 100644
--- a/src/protocols/rdp/guac_ai/ai_messages.h
+++ b/src/protocols/rdp/guac_ai/ai_messages.h
@@ -32,6 +32,12 @@
 #endif
 
 /**
+ * The format tag associated with raw wave audio (WAVE_FORMAT_PCM). This format
+ * is required to be supported by all RDP servers.
+ */
+#define GUAC_RDP_WAVE_FORMAT_PCM 0x01
+
+/**
  * The message ID associated with the AUDIO_INPUT Version PDU. The Version PDU
  * is sent by both the client and the server to indicate their version of the
  * AUDIO_INPUT channel protocol (which must always be 1).
@@ -80,6 +86,59 @@
 #define GUAC_RDP_MSG_SNDIN_FORMATCHANGE 0x07
 
 /**
+ * An AUDIO_INPUT format, analogous to the AUDIO_FORMAT structure defined
+ * within Microsoft's RDP documentation.
+ */
+typedef struct guac_rdp_ai_format {
+
+    /**
+     * The "format tag" denoting the overall format of audio data received,
+     * such as WAVE_FORMAT_PCM.
+     */
+    UINT16 tag;
+
+    /**
+     * The number of audio channels.
+     */
+    UINT16 channels;
+
+    /**
+     * The number of samples per second.
+     */
+    UINT32 rate;
+
+    /**
+     * The average number of bytes required for one second of audio.
+     */
+    UINT32 bytes_per_sec;
+
+    /**
+     * The absolute minimum number of bytes required to process audio in this
+     * format.
+     */
+    UINT16 block_align;
+
+    /**
+     * The number of bits per sample.
+     */
+    UINT16 bps;
+
+    /**
+     * The size of the arbitrary data block, if any. The meaning of the data
+     * within the arbitrary data block is determined by the format tag.
+     * WAVE_FORMAT_PCM audio has no associated arbitrary data.
+     */
+    UINT16 data_size;
+
+    /**
+     * Optional arbitrary data whose meaning is determined by the format tag.
+     * WAVE_FORMAT_PCM audio has no associated arbitrary data.
+     */
+    BYTE* data;
+
+} guac_rdp_ai_format;
+
+/**
  * Processes a Version PDU received from the RDP server. The Version PDU is
  * sent by the server to indicate its version of the AUDIO_INPUT channel
  * protocol (which must always be 1).


[19/26] incubator-guacamole-server git commit: GUACAMOLE-25: Implement parsing of audio mimetypes.

Posted by jm...@apache.org.
GUACAMOLE-25: Implement parsing of audio mimetypes.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/320f564d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/320f564d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/320f564d

Branch: refs/heads/master
Commit: 320f564daf2e67ce2e746b1b5697320dc191815f
Parents: 8ccf61e
Author: Michael Jumper <mj...@apache.org>
Authored: Wed May 11 13:34:29 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 13:50:29 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/audio_input.c | 114 +++++++++++++++++++++++++++++++++++
 1 file changed, 114 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/320f564d/src/protocols/rdp/audio_input.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.c b/src/protocols/rdp/audio_input.c
index f2fd84a..b7f605d 100644
--- a/src/protocols/rdp/audio_input.c
+++ b/src/protocols/rdp/audio_input.c
@@ -30,16 +30,130 @@
 #include <guacamole/stream.h>
 #include <guacamole/user.h>
 
+#include <errno.h>
 #include <stdlib.h>
 #include <pthread.h>
 
+/**
+ * Parses the given raw audio mimetype, producing the corresponding rate,
+ * number of channels, and bytes per sample.
+ *
+ * @param mimetype
+ *     The raw auduio mimetype to parse.
+ *
+ * @param rate
+ *     A pointer to an int where the sample rate for the PCM format described
+ *     by the given mimetype should be stored.
+ *
+ * @param channels
+ *     A pointer to an int where the number of channels used by the PCM format
+ *     described by the given mimetype should be stored.
+ *
+ * @param bps
+ *     A pointer to an int where the number of bytes used the PCM format for
+ *     each sample (independent of number of channels) described by the given
+ *     mimetype should be stored.
+ *
+ * @return
+ *     Zero if the given mimetype is a raw audio mimetype and has been parsed
+ *     successfully, non-zero otherwise.
+ */
+static int guac_rdp_audio_parse_mimetype(const char* mimetype,
+        int* rate, int* channels, int* bps) {
+
+    int parsed_rate = -1;
+    int parsed_channels = 1;
+    int parsed_bps;
+
+    /* PCM audio with one byte per sample */
+    if (strncmp(mimetype, "audio/L8;", 9) == 0) {
+        mimetype += 8; /* Advance to semicolon ONLY */
+        parsed_bps = 1;
+    }
+
+    /* PCM audio with two bytes per sample */
+    else if (strncmp(mimetype, "audio/L16;", 10) == 0) {
+        mimetype += 9; /* Advance to semicolon ONLY */
+        parsed_bps = 2;
+    }
+
+    /* Unsupported mimetype */
+    else
+        return 1;
+
+    /* Parse each parameter name/value pair within the mimetype */
+    do {
+
+        /* Advance to first character of parameter (current is either a
+         * semicolon or a comma) */
+        mimetype++;
+
+        /* Parse number of channels */
+        if (strncmp(mimetype, "channels=", 9) == 0) {
+
+            mimetype += 9;
+            parsed_channels = strtol(mimetype, (char**) &mimetype, 10);
+
+            /* Fail if value invalid / out of range */
+            if (errno == EINVAL || errno == ERANGE)
+                return 1;
+
+        }
+
+        /* Parse number of rate */
+        else if (strncmp(mimetype, "rate=", 5) == 0) {
+
+            mimetype += 5;
+            parsed_rate = strtol(mimetype, (char**) &mimetype, 10);
+
+            /* Fail if value invalid / out of range */
+            if (errno == EINVAL || errno == ERANGE)
+                return 1;
+
+        }
+
+        /* Advance to next parameter */
+        mimetype = strchr(mimetype, ',');
+
+    } while (mimetype != NULL);
+
+    /* Mimetype is invalid if rate was not specified */
+    if (rate == -1)
+        return 1;
+
+    /* Parse success */
+    *rate = parsed_rate;
+    *channels = parsed_channels;
+    *bps = parsed_bps;
+
+    return 0;
+
+}
+
 int guac_rdp_audio_handler(guac_user* user, guac_stream* stream,
         char* mimetype) {
 
     guac_client* client = user->client;
     guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
 
+    int rate;
+    int channels;
+    int bps;
+
+    /* Parse mimetype, abort on parse error */
+    if (guac_rdp_audio_parse_mimetype(mimetype, &rate, &channels, &bps)) {
+        guac_user_log(user, GUAC_LOG_WARN, "Denying user audio stream with "
+                "unsupported mimetype: \"%s\"", mimetype);
+        guac_protocol_send_ack(user->socket, stream, "Unsupported audio "
+                "mimetype", GUAC_PROTOCOL_STATUS_CLIENT_BAD_TYPE);
+        return 0;
+    }
+
     /* FIXME: Assuming mimetype of "audio/L16;rate=44100,channels=2" */
+    else {
+        guac_user_log(user, GUAC_LOG_DEBUG, "rate=%i, channels=%i, bps=%i",
+                rate, channels, bps);
+    }
 
     /* Init stream data */
     stream->blob_handler = guac_rdp_audio_blob_handler;


[04/26] incubator-guacamole-server git commit: GUACAMOLE-25: Fix pointer update in audio input buffer transfer.

Posted by jm...@apache.org.
GUACAMOLE-25: Fix pointer update in audio input buffer transfer.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/166eba11
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/166eba11
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/166eba11

Branch: refs/heads/master
Commit: 166eba11b728ffa4501bea9d0ad7afaf9a755911
Parents: 4e4dbd6
Author: Michael Jumper <mj...@apache.org>
Authored: Sun May 1 00:04:40 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 13:50:28 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/audio_input.c | 3 +++
 1 file changed, 3 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/166eba11/src/protocols/rdp/audio_input.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.c b/src/protocols/rdp/audio_input.c
index 1bea175..8839d35 100644
--- a/src/protocols/rdp/audio_input.c
+++ b/src/protocols/rdp/audio_input.c
@@ -128,6 +128,9 @@ void guac_rdp_audio_buffer_write(guac_rdp_audio_buffer* audio_buffer,
         length -= chunk_size;
         audio_buffer->bytes_written += chunk_size;
 
+        /* Advance to next chunk */
+        buffer += chunk_size;
+
         /* Invoke flush handler if full */
         if (audio_buffer->bytes_written == audio_buffer->packet_size) {
 


[08/26] incubator-guacamole-server git commit: GUACAMOLE-25: Allocate proper number of argument entries.

Posted by jm...@apache.org.
GUACAMOLE-25: Allocate proper number of argument entries.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/9cd89e65
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/9cd89e65
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/9cd89e65

Branch: refs/heads/master
Commit: 9cd89e6580615249cb0dbd8773934b871bc0ddb0
Parents: 4fdcfeb
Author: Michael Jumper <mj...@apache.org>
Authored: Sat Apr 16 21:44:14 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 13:50:28 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/audio_input.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/9cd89e65/src/protocols/rdp/audio_input.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.c b/src/protocols/rdp/audio_input.c
index b5c3f96..9d5d505 100644
--- a/src/protocols/rdp/audio_input.c
+++ b/src/protocols/rdp/audio_input.c
@@ -69,8 +69,8 @@ void guac_rdp_audio_load_plugin(rdpContext* context) {
 
     /* Add "AUDIO_INPUT" channel */
     ADDIN_ARGV* args = malloc(sizeof(ADDIN_ARGV));
-    args->argc = 1;
-    args->argv = malloc(sizeof(char**) * 1);
+    args->argc = 2;
+    args->argv = malloc(sizeof(char**) * 2);
     args->argv[0] = strdup("guacai");
     args->argv[1] = guac_rdp_ptr_to_string(client);
     freerdp_dynamic_channel_collection_add(context->settings, args);


[22/26] incubator-guacamole-server git commit: GUACAMOLE-25: Store PCM format expected by RDP server.

Posted by jm...@apache.org.
GUACAMOLE-25: Store PCM format expected by RDP server.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/1c2890b4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/1c2890b4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/1c2890b4

Branch: refs/heads/master
Commit: 1c2890b47c77b324efb6420df43998eff7104333
Parents: ad00cce
Author: Michael Jumper <mj...@apache.org>
Authored: Thu May 26 10:39:33 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Thu May 26 10:39:33 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/audio_input.c         | 35 +++++++++++++++++-----
 src/protocols/rdp/audio_input.h         | 44 ++++++++++++++++++----------
 src/protocols/rdp/guac_ai/ai_messages.c | 22 +++++++++-----
 3 files changed, 72 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/1c2890b4/src/protocols/rdp/audio_input.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.c b/src/protocols/rdp/audio_input.c
index 9e88fb5..0eb757d 100644
--- a/src/protocols/rdp/audio_input.c
+++ b/src/protocols/rdp/audio_input.c
@@ -250,28 +250,49 @@ void guac_rdp_audio_buffer_set_stream(guac_rdp_audio_buffer* audio_buffer,
     guac_rdp_audio_buffer_ack(audio_buffer,
             "OK", GUAC_PROTOCOL_STATUS_SUCCESS);
 
+    guac_user_log(user, GUAC_LOG_DEBUG, "User is requesting to provide audio "
+            "input as %i-channel, %i Hz PCM audio at %i bytes/sample.",
+            audio_buffer->in_format.channels,
+            audio_buffer->in_format.rate,
+            audio_buffer->in_format.bps);
+
     pthread_mutex_unlock(&(audio_buffer->lock));
 
 }
 
-void guac_rdp_audio_buffer_begin(guac_rdp_audio_buffer* audio_buffer,
-        int rate, int channels, int bps, int packet_size,
-        guac_rdp_audio_buffer_flush_handler* flush_handler, void* data) {
+void guac_rdp_audio_buffer_set_output(guac_rdp_audio_buffer* audio_buffer,
+        int rate, int channels, int bps) {
 
     pthread_mutex_lock(&(audio_buffer->lock));
 
-    /* Reset buffer state to provided values */
-    audio_buffer->bytes_written = 0;
+    /* Set output format */
     audio_buffer->out_format.rate = rate;
     audio_buffer->out_format.channels = channels;
     audio_buffer->out_format.bps = bps;
-    audio_buffer->packet_size = packet_size;
+
+    pthread_mutex_unlock(&(audio_buffer->lock));
+
+}
+
+void guac_rdp_audio_buffer_begin(guac_rdp_audio_buffer* audio_buffer,
+        int packet_frames, guac_rdp_audio_buffer_flush_handler* flush_handler,
+        void* data) {
+
+    pthread_mutex_lock(&(audio_buffer->lock));
+
+    /* Reset buffer state to provided values */
+    audio_buffer->bytes_written = 0;
     audio_buffer->flush_handler = flush_handler;
     audio_buffer->data = data;
 
+    /* Calculate size of each packet in bytes */
+    audio_buffer->packet_size = packet_frames
+                              * audio_buffer->out_format.channels
+                              * audio_buffer->out_format.bps;
+
     /* Allocate new buffer */
     free(audio_buffer->packet);
-    audio_buffer->packet = malloc(packet_size);
+    audio_buffer->packet = malloc(audio_buffer->packet_size);
 
     /* Acknowledge stream creation (if stream is ready to receive) */
     guac_rdp_audio_buffer_ack(audio_buffer,

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/1c2890b4/src/protocols/rdp/audio_input.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.h b/src/protocols/rdp/audio_input.h
index 0970671..87eee9a 100644
--- a/src/protocols/rdp/audio_input.h
+++ b/src/protocols/rdp/audio_input.h
@@ -181,28 +181,42 @@ void guac_rdp_audio_buffer_set_stream(guac_rdp_audio_buffer* audio_buffer,
         guac_user* user, guac_stream* stream, int rate, int channels, int bps);
 
 /**
- * Begins handling of audio data received via guac_rdp_audio_buffer_write() and
- * allocates the necessary underlying packet buffer. Audio packets of exactly
- * packet_size bytes will be flushed as available using the provided
- * flush_handler.
+ * Defines the output format that should be used by the audio buffer when
+ * flushing packets of audio data received via guac_rdp_audio_buffer_write().
+ * As this format determines how the underlying packet buffer will be
+ * allocated, this function MUST be called prior to the call to
+ * guac_rdp_audio_buffer_begin().
  *
  * @param audio_buffer
- *     The audio buffer to begin.
+ *     The audio buffer to set the output format of.
  *
  * @param rate
- *     The rate of the audio stream expected by RDP, if any, in samples per
- *     second.
+ *     The rate of the audio stream expected by RDP, in samples per second.
  *
  * @param channels
- *     The number of channels included in the audio stream expected by RDP, if
- *     any.
+ *     The number of channels included in the audio stream expected by RDP.
  *
  * @param bps
- *     The size of each sample within the audio stream expected by RDP, if any,
- *     in bytes.
+ *     The size of each sample within the audio stream expected by RDP, in
+ *     bytes.
+ */
+void guac_rdp_audio_buffer_set_output(guac_rdp_audio_buffer* audio_buffer,
+        int rate, int channels, int bps);
+
+/**
+ * Begins handling of audio data received via guac_rdp_audio_buffer_write() and
+ * allocates the necessary underlying packet buffer. Audio packets having
+ * exactly packet_frames frames will be flushed as available using the provided
+ * flush_handler. An audio frame is a set of single samples, one sample per
+ * channel. The guac_rdp_audio_buffer_set_output() function MUST have
+ * been invoked first.
  *
- * @param packet_size
- *     The number of bytes to include in all audio packets provided to the
+ * @param audio_buffer
+ *     The audio buffer to begin.
+ *
+ * @param packet_frames
+ *     The exact number of frames (a set of samples, one for each channel)
+ *     which MUST be included in all audio packets provided to the
  *     given flush_handler.
  *
  * @param flush_handler
@@ -213,8 +227,8 @@ void guac_rdp_audio_buffer_set_stream(guac_rdp_audio_buffer* audio_buffer,
  *     needs to be flushed.
  */
 void guac_rdp_audio_buffer_begin(guac_rdp_audio_buffer* audio_buffer,
-        int rate, int channels, int bps, int packet_size,
-        guac_rdp_audio_buffer_flush_handler* flush_handler, void* data);
+        int packet_frames, guac_rdp_audio_buffer_flush_handler* flush_handler,
+        void* data);
 
 /**
  * Writes the given buffer of audio data to the given audio buffer. A new

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/1c2890b4/src/protocols/rdp/guac_ai/ai_messages.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/guac_ai/ai_messages.c b/src/protocols/rdp/guac_ai/ai_messages.c
index eeb3e28..c346587 100644
--- a/src/protocols/rdp/guac_ai/ai_messages.c
+++ b/src/protocols/rdp/guac_ai/ai_messages.c
@@ -251,6 +251,9 @@ void guac_rdp_ai_process_version(guac_client* client,
 void guac_rdp_ai_process_formats(guac_client* client,
         IWTSVirtualChannel* channel, wStream* stream) {
 
+    guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
+    guac_rdp_audio_buffer* audio_buffer = rdp_client->audio_input;
+
     UINT32 num_formats;
     Stream_Read_UINT32(stream, num_formats); /* NumFormats */
     Stream_Seek_UINT32(stream); /* cbSizeFormatsPacket (MUST BE IGNORED) */
@@ -265,6 +268,10 @@ void guac_rdp_ai_process_formats(guac_client* client,
         if (format.tag != GUAC_RDP_WAVE_FORMAT_PCM)
             continue;
 
+        /* Set output format of internal audio buffer to match RDP server */
+        guac_rdp_audio_buffer_set_output(audio_buffer, format.rate,
+                format.channels, format.bps / 8);
+
         /* Accept single format */
         guac_rdp_ai_send_incoming_data(channel);
         guac_rdp_ai_send_formats(channel, &format, 1);
@@ -301,18 +308,19 @@ void guac_rdp_ai_process_open(guac_client* client,
     Stream_Read_UINT32(stream, packet_frames); /* FramesPerPacket */
     Stream_Read_UINT32(stream, initial_format); /* InitialFormat */
 
-    /* STUB */
-    guac_client_log(client, GUAC_LOG_DEBUG, "AUDIO_INPUT: open: "
-            "packet_frames=%i, initial_format=%i",
-            packet_frames, initial_format);
+    guac_client_log(client, GUAC_LOG_DEBUG, "RDP server is accepting audio "
+            "input as %i-channel, %i Hz PCM audio at %i bytes/sample.",
+            audio_buffer->out_format.channels,
+            audio_buffer->out_format.rate,
+            audio_buffer->out_format.bps);
 
     /* Success */
     guac_rdp_ai_send_formatchange(channel, initial_format);
     guac_rdp_ai_send_open_reply(channel, 0);
 
-    /* FIXME: Assuming mimetype of 16-bit 44100 Hz stereo PCM */
-    guac_rdp_audio_buffer_begin(audio_buffer, packet_frames * 2 * 2,
-            44100, 2, 2, guac_rdp_ai_flush_packet, channel);
+    /* Begin receiving audio data */
+    guac_rdp_audio_buffer_begin(audio_buffer, packet_frames,
+            guac_rdp_ai_flush_packet, channel);
 
 }
 


[18/26] incubator-guacamole-server git commit: GUACAMOLE-25: Store input and output audio format.

Posted by jm...@apache.org.
GUACAMOLE-25: Store input and output audio format.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/533a47f0
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/533a47f0
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/533a47f0

Branch: refs/heads/master
Commit: 533a47f06da3559ab66161fe8af8f431add167f0
Parents: 320f564
Author: Michael Jumper <mj...@apache.org>
Authored: Wed May 11 13:48:40 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 13:50:29 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/audio_input.c         | 27 ++++++-----
 src/protocols/rdp/audio_input.h         | 69 ++++++++++++++++++++++++++--
 src/protocols/rdp/guac_ai/ai_messages.c |  2 +-
 3 files changed, 82 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/533a47f0/src/protocols/rdp/audio_input.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.c b/src/protocols/rdp/audio_input.c
index b7f605d..b2f61bd 100644
--- a/src/protocols/rdp/audio_input.c
+++ b/src/protocols/rdp/audio_input.c
@@ -118,7 +118,7 @@ static int guac_rdp_audio_parse_mimetype(const char* mimetype,
     } while (mimetype != NULL);
 
     /* Mimetype is invalid if rate was not specified */
-    if (rate == -1)
+    if (parsed_rate == -1)
         return 1;
 
     /* Parse success */
@@ -142,25 +142,20 @@ int guac_rdp_audio_handler(guac_user* user, guac_stream* stream,
 
     /* Parse mimetype, abort on parse error */
     if (guac_rdp_audio_parse_mimetype(mimetype, &rate, &channels, &bps)) {
-        guac_user_log(user, GUAC_LOG_WARN, "Denying user audio stream with "
+        guac_user_log(user, GUAC_LOG_WARNING, "Denying user audio stream with "
                 "unsupported mimetype: \"%s\"", mimetype);
         guac_protocol_send_ack(user->socket, stream, "Unsupported audio "
                 "mimetype", GUAC_PROTOCOL_STATUS_CLIENT_BAD_TYPE);
         return 0;
     }
 
-    /* FIXME: Assuming mimetype of "audio/L16;rate=44100,channels=2" */
-    else {
-        guac_user_log(user, GUAC_LOG_DEBUG, "rate=%i, channels=%i, bps=%i",
-                rate, channels, bps);
-    }
-
     /* Init stream data */
     stream->blob_handler = guac_rdp_audio_blob_handler;
     stream->end_handler = guac_rdp_audio_end_handler;
 
     /* Associate stream with audio buffer */
-    guac_rdp_audio_buffer_set_stream(rdp_client->audio_input, user, stream);
+    guac_rdp_audio_buffer_set_stream(rdp_client->audio_input, user, stream,
+            rate, channels, bps);
 
     return 0;
 
@@ -240,13 +235,16 @@ static void guac_rdp_audio_buffer_ack(guac_rdp_audio_buffer* audio_buffer,
 }
 
 void guac_rdp_audio_buffer_set_stream(guac_rdp_audio_buffer* audio_buffer,
-        guac_user* user, guac_stream* stream) {
+        guac_user* user, guac_stream* stream, int rate, int channels, int bps) {
 
     pthread_mutex_lock(&(audio_buffer->lock));
 
     /* Associate received stream */
     audio_buffer->user = user;
     audio_buffer->stream = stream;
+    audio_buffer->in_rate = rate;
+    audio_buffer->in_channels = channels;
+    audio_buffer->in_bps = bps;
 
     /* Acknowledge stream creation (if buffer is ready to receive) */
     guac_rdp_audio_buffer_ack(audio_buffer,
@@ -257,13 +255,16 @@ void guac_rdp_audio_buffer_set_stream(guac_rdp_audio_buffer* audio_buffer,
 }
 
 void guac_rdp_audio_buffer_begin(guac_rdp_audio_buffer* audio_buffer,
-        int packet_size, guac_rdp_audio_buffer_flush_handler* flush_handler,
-        void* data) {
+        int rate, int channels, int bps, int packet_size,
+        guac_rdp_audio_buffer_flush_handler* flush_handler, void* data) {
 
     pthread_mutex_lock(&(audio_buffer->lock));
 
     /* Reset buffer state to provided values */
     audio_buffer->bytes_written = 0;
+    audio_buffer->out_rate = rate;
+    audio_buffer->out_channels = channels;
+    audio_buffer->out_bps = bps;
     audio_buffer->packet_size = packet_size;
     audio_buffer->flush_handler = flush_handler;
     audio_buffer->data = data;
@@ -285,6 +286,8 @@ void guac_rdp_audio_buffer_write(guac_rdp_audio_buffer* audio_buffer,
 
     pthread_mutex_lock(&(audio_buffer->lock));
 
+    /* FIXME: Assuming mimetype of "audio/L16;rate=44100,channels=2" */
+
     /* Ignore packet if there is no buffer */
     if (audio_buffer->packet_size == 0 || audio_buffer->packet == NULL) {
         pthread_mutex_unlock(&(audio_buffer->lock));

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/533a47f0/src/protocols/rdp/audio_input.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.h b/src/protocols/rdp/audio_input.h
index e13b41e..2514b50 100644
--- a/src/protocols/rdp/audio_input.h
+++ b/src/protocols/rdp/audio_input.h
@@ -74,6 +74,45 @@ typedef struct guac_rdp_audio_buffer {
     guac_stream* stream;
 
     /**
+     * The rate of the audio stream being received from the user, if any, in
+     * samples per second. If no stream is yet associated, this value is
+     * undefined.
+     */
+    int in_rate;
+
+    /**
+     * The number of channels included in the audio stream being received from
+     * the user, if any. If no stream is yet associated, this value is
+     * undefined.
+     */
+    int in_channels;
+
+    /**
+     * The size of each sample within the audio stream being received from the
+     * user, if any, in bytes. If no stream is yet associated, this value is
+     * undefined.
+     */
+    int in_bps;
+
+    /**
+     * The rate of the audio stream expected by RDP, if any, in samples per
+     * second. If no stream is yet associated, this value is undefined.
+     */
+    int out_rate;
+
+    /**
+     * The number of channels included in the audio stream expected by RDP, if
+     * any. If no stream is yet associated, this value is undefined.
+     */
+    int out_channels;
+
+    /**
+     * The size of each sample within the audio stream expected by RDP, if any,
+     * in bytes. If no stream is yet associated, this value is undefined.
+     */
+    int out_bps;
+
+    /**
      * The size that each audio packet must be, in bytes. The packet buffer
      * within this structure will be at least this size.
      */
@@ -127,9 +166,21 @@ guac_rdp_audio_buffer* guac_rdp_audio_buffer_alloc();
  *
  * @param stream
  *     The guac_stream object representing the audio stream.
+ *
+ * @param rate
+ *     The rate of the audio stream being received from the user, if any, in
+ *     samples per second.
+ *
+ * @param channels
+ *     The number of channels included in the audio stream being received from
+ *     the user, if any.
+ *
+ * @param bps
+ *     The size of each sample within the audio stream being received from the
+ *     user, if any, in bytes.
  */
 void guac_rdp_audio_buffer_set_stream(guac_rdp_audio_buffer* audio_buffer,
-        guac_user* user, guac_stream* stream);
+        guac_user* user, guac_stream* stream, int rate, int channels, int bps);
 
 /**
  * Begins handling of audio data received via guac_rdp_audio_buffer_write() and
@@ -140,6 +191,18 @@ void guac_rdp_audio_buffer_set_stream(guac_rdp_audio_buffer* audio_buffer,
  * @param audio_buffer
  *     The audio buffer to begin.
  *
+ * @param rate
+ *     The rate of the audio stream expected by RDP, if any, in samples per
+ *     second.
+ *
+ * @param channels
+ *     The number of channels included in the audio stream expected by RDP, if
+ *     any.
+ *
+ * @param bps
+ *     The size of each sample within the audio stream expected by RDP, if any,
+ *     in bytes.
+ *
  * @param packet_size
  *     The number of bytes to include in all audio packets provided to the
  *     given flush_handler.
@@ -152,8 +215,8 @@ void guac_rdp_audio_buffer_set_stream(guac_rdp_audio_buffer* audio_buffer,
  *     needs to be flushed.
  */
 void guac_rdp_audio_buffer_begin(guac_rdp_audio_buffer* audio_buffer,
-        int packet_size, guac_rdp_audio_buffer_flush_handler* flush_handler,
-        void* data);
+        int rate, int channels, int bps, int packet_size,
+        guac_rdp_audio_buffer_flush_handler* flush_handler, void* data);
 
 /**
  * Writes the given buffer of audio data to the given audio buffer. A new

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/533a47f0/src/protocols/rdp/guac_ai/ai_messages.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/guac_ai/ai_messages.c b/src/protocols/rdp/guac_ai/ai_messages.c
index b0eb6cf..520416c 100644
--- a/src/protocols/rdp/guac_ai/ai_messages.c
+++ b/src/protocols/rdp/guac_ai/ai_messages.c
@@ -312,7 +312,7 @@ void guac_rdp_ai_process_open(guac_client* client,
 
     /* FIXME: Assuming mimetype of 16-bit 44100 Hz stereo PCM */
     guac_rdp_audio_buffer_begin(audio_buffer, packet_frames * 2 * 2,
-            guac_rdp_ai_flush_packet, channel);
+            44100, 2, 2, guac_rdp_ai_flush_packet, channel);
 
 }
 


[11/26] incubator-guacamole-server git commit: GUACAMOLE-25: Fix configure test for FreeRDP variations.

Posted by jm...@apache.org.
GUACAMOLE-25: Fix configure test for FreeRDP variations.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/4e4dbd6a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/4e4dbd6a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/4e4dbd6a

Branch: refs/heads/master
Commit: 4e4dbd6a2d9e882a2a23baf758a209621b5334fc
Parents: 9d5871a
Author: Michael Jumper <mj...@apache.org>
Authored: Wed Apr 20 22:02:01 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 13:50:28 2016 -0700

----------------------------------------------------------------------
 configure.ac                           | 6 +++++-
 src/protocols/rdp/guac_ai/ai_service.c | 2 +-
 2 files changed, 6 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/4e4dbd6a/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 04cb6bb..7dec629 100644
--- a/configure.ac
+++ b/configure.ac
@@ -779,7 +779,11 @@ then
                                             wStream* stream);
                                         IWTSVirtualChannelCallback cb = {
                                             .OnDataReceived = __data_received
-                                        };]])],
+                                        };
+                                        int main() {
+                                            return
+                                                cb.OnDataReceived(NULL, NULL);
+                                        }]])],
                       [AC_MSG_RESULT([yes])],
                       [AC_MSG_RESULT([no])
                        AC_DEFINE([LEGACY_IWTSVIRTUALCHANNELCALLBACK],,

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/4e4dbd6a/src/protocols/rdp/guac_ai/ai_service.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/guac_ai/ai_service.c b/src/protocols/rdp/guac_ai/ai_service.c
index 945f039..2fbf2ac 100644
--- a/src/protocols/rdp/guac_ai/ai_service.c
+++ b/src/protocols/rdp/guac_ai/ai_service.c
@@ -95,7 +95,7 @@ static void guac_rdp_ai_handle_data(guac_client* client,
 
 }
 
-#if LEGACY_IWTSVIRTUALCHANNELCALLBACK
+#ifdef LEGACY_IWTSVIRTUALCHANNELCALLBACK
 /**
  * Callback which is invoked when data is received along a connection to the
  * AUDIO_INPUT plugin. This callback is specific to FreeRDP 1.1 and older.


[06/26] incubator-guacamole-server git commit: GUACAMOLE-25: Delay sending of "ack" until RDP has opened the AUDIO_INPUT stream. Close audio stream with another "ack" when RDP has closed the AUDIO_INPUT stream.

Posted by jm...@apache.org.
GUACAMOLE-25: Delay sending of "ack" until RDP has opened the AUDIO_INPUT stream. Close audio stream with another "ack" when RDP has closed the AUDIO_INPUT stream.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/46bdf069
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/46bdf069
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/46bdf069

Branch: refs/heads/master
Commit: 46bdf0692fca50d74c964701f163cc0df58ba76b
Parents: 5030c06
Author: Michael Jumper <mj...@apache.org>
Authored: Mon May 2 00:11:38 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 13:50:28 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/audio_input.c | 97 ++++++++++++++++++++++++++++++++++--
 src/protocols/rdp/audio_input.h | 39 +++++++++++++++
 2 files changed, 131 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/46bdf069/src/protocols/rdp/audio_input.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.c b/src/protocols/rdp/audio_input.c
index 8839d35..93c492b 100644
--- a/src/protocols/rdp/audio_input.c
+++ b/src/protocols/rdp/audio_input.c
@@ -30,19 +30,22 @@
 #include <guacamole/user.h>
 
 #include <stdlib.h>
+#include <pthread.h>
 
 int guac_rdp_audio_handler(guac_user* user, guac_stream* stream,
         char* mimetype) {
 
+    guac_client* client = user->client;
+    guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
+
     /* FIXME: Assuming mimetype of "audio/L16;rate=44100,channels=2" */
 
     /* Init stream data */
     stream->blob_handler = guac_rdp_audio_blob_handler;
     stream->end_handler = guac_rdp_audio_end_handler;
 
-    guac_protocol_send_ack(user->socket, stream,
-            "OK", GUAC_PROTOCOL_STATUS_SUCCESS);
-    guac_socket_flush(user->socket);
+    /* Associate stream with audio buffer */
+    guac_rdp_audio_buffer_set_stream(rdp_client->audio_input, user, stream);
 
     return 0;
 
@@ -83,13 +86,72 @@ void guac_rdp_audio_load_plugin(rdpContext* context) {
 }
 
 guac_rdp_audio_buffer* guac_rdp_audio_buffer_alloc() {
-    return calloc(1, sizeof(guac_rdp_audio_buffer));
+    guac_rdp_audio_buffer* buffer = calloc(1, sizeof(guac_rdp_audio_buffer));
+    pthread_mutex_init(&(buffer->lock), NULL);
+    return buffer;
+}
+
+/**
+ * Sends an "ack" instruction over the socket associated with the Guacamole
+ * stream over which audio data is being received. The "ack" instruction will
+ * only be sent if the Guacamole audio stream has been established (through
+ * receipt of an "audio" instruction), is still open (has not received an "end"
+ * instruction nor been associated with an "ack" having an error code), and is
+ * associated with an active RDP AUDIO_INPUT channel.
+ *
+ * @param audio_buffer
+ *     The audio buffer associated with the guac_stream for which the "ack"
+ *     instruction should be sent, if any. If there is no associated
+ *     guac_stream, this function has no effect.
+ *
+ * @param message
+ *     An arbitrary human-readable message to send along with the "ack".
+ *
+ * @param status
+ *     The Guacamole protocol status code to send with the "ack". This should
+ *     be GUAC_PROTOCOL_STATUS_SUCCESS if the audio stream has been set up
+ *     successfully or GUAC_PROTOCOL_STATUS_RESOURCE_CLOSED if the audio stream
+ *     has been closed (but may usable again if reopened).
+ */
+static void guac_rdp_audio_buffer_ack(guac_rdp_audio_buffer* audio_buffer,
+        const char* message, guac_protocol_status status) {
+
+    guac_user* user = audio_buffer->user;
+    guac_stream* stream = audio_buffer->stream;
+
+    /* Do not send ack unless both sides of the audio stream are ready */
+    if (user == NULL || stream == NULL || audio_buffer->packet == NULL)
+        return;
+
+    /* Send ack instruction */
+    guac_protocol_send_ack(user->socket, stream, message, status);
+    guac_socket_flush(user->socket);
+
+}
+
+void guac_rdp_audio_buffer_set_stream(guac_rdp_audio_buffer* audio_buffer,
+        guac_user* user, guac_stream* stream) {
+
+    pthread_mutex_lock(&(audio_buffer->lock));
+
+    /* Associate received stream */
+    audio_buffer->user = user;
+    audio_buffer->stream = stream;
+
+    /* Acknowledge stream creation (if buffer is ready to receive) */
+    guac_rdp_audio_buffer_ack(audio_buffer,
+            "OK", GUAC_PROTOCOL_STATUS_SUCCESS);
+
+    pthread_mutex_unlock(&(audio_buffer->lock));
+
 }
 
 void guac_rdp_audio_buffer_begin(guac_rdp_audio_buffer* audio_buffer,
         int packet_size, guac_rdp_audio_buffer_flush_handler* flush_handler,
         void* data) {
 
+    pthread_mutex_lock(&(audio_buffer->lock));
+
     /* Reset buffer state to provided values */
     audio_buffer->bytes_written = 0;
     audio_buffer->packet_size = packet_size;
@@ -100,14 +162,24 @@ void guac_rdp_audio_buffer_begin(guac_rdp_audio_buffer* audio_buffer,
     free(audio_buffer->packet);
     audio_buffer->packet = malloc(packet_size);
 
+    /* Acknowledge stream creation (if stream is ready to receive) */
+    guac_rdp_audio_buffer_ack(audio_buffer,
+            "OK", GUAC_PROTOCOL_STATUS_SUCCESS);
+
+    pthread_mutex_unlock(&(audio_buffer->lock));
+
 }
 
 void guac_rdp_audio_buffer_write(guac_rdp_audio_buffer* audio_buffer,
         char* buffer, int length) {
 
+    pthread_mutex_lock(&(audio_buffer->lock));
+
     /* Ignore packet if there is no buffer */
-    if (audio_buffer->packet_size == 0 || audio_buffer->packet == NULL)
+    if (audio_buffer->packet_size == 0 || audio_buffer->packet == NULL) {
+        pthread_mutex_unlock(&(audio_buffer->lock));
         return;
+    }
 
     /* Continuously write packets until no data remains */
     while (length > 0) {
@@ -146,10 +218,22 @@ void guac_rdp_audio_buffer_write(guac_rdp_audio_buffer* audio_buffer,
 
     } /* end packet write loop */
 
+    pthread_mutex_unlock(&(audio_buffer->lock));
+
 }
 
 void guac_rdp_audio_buffer_end(guac_rdp_audio_buffer* audio_buffer) {
 
+    pthread_mutex_lock(&(audio_buffer->lock));
+
+    /* The stream is now closed */
+    guac_rdp_audio_buffer_ack(audio_buffer,
+            "CLOSED", GUAC_PROTOCOL_STATUS_RESOURCE_CLOSED);
+
+    /* Unset user and stream */
+    audio_buffer->user = NULL;
+    audio_buffer->stream = NULL;
+
     /* Reset buffer state */
     audio_buffer->bytes_written = 0;
     audio_buffer->packet_size = 0;
@@ -159,9 +243,12 @@ void guac_rdp_audio_buffer_end(guac_rdp_audio_buffer* audio_buffer) {
     free(audio_buffer->packet);
     audio_buffer->packet = NULL;
 
+    pthread_mutex_unlock(&(audio_buffer->lock));
+
 }
 
 void guac_rdp_audio_buffer_free(guac_rdp_audio_buffer* audio_buffer) {
+    pthread_mutex_destroy(&(audio_buffer->lock));
     free(audio_buffer->packet);
     free(audio_buffer);
 }

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/46bdf069/src/protocols/rdp/audio_input.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.h b/src/protocols/rdp/audio_input.h
index c89de15..776f0a5 100644
--- a/src/protocols/rdp/audio_input.h
+++ b/src/protocols/rdp/audio_input.h
@@ -23,8 +23,11 @@
 #include "config.h"
 
 #include <freerdp/freerdp.h>
+#include <guacamole/stream.h>
 #include <guacamole/user.h>
 
+#include <pthread.h>
+
 /**
  * Handler which is invoked when a guac_rdp_audio_buffer's internal packet
  * buffer has reached capacity and must be flushed.
@@ -52,6 +55,24 @@ typedef void guac_rdp_audio_buffer_flush_handler(char* buffer, int length,
 typedef struct guac_rdp_audio_buffer {
 
     /**
+     * Lock which is acquired/released to ensure accesses to the audio buffer
+     * are atomic.
+     */
+    pthread_mutex_t lock;
+
+    /**
+     * The user from which this audio buffer will receive data. If no user has
+     * yet opened an associated audio stream, this will be NULL.
+     */
+    guac_user* user;
+
+    /**
+     * The stream from which this audio buffer will receive data. If no user
+     * has yet opened an associated audio stream, this will be NULL.
+     */
+    guac_stream* stream;
+
+    /**
      * The size that each audio packet must be, in bytes. The packet buffer
      * within this structure will be at least this size.
      */
@@ -92,6 +113,24 @@ typedef struct guac_rdp_audio_buffer {
 guac_rdp_audio_buffer* guac_rdp_audio_buffer_alloc();
 
 /**
+ * Associates the given audio buffer with the underlying audio stream which
+ * has been received from the given Guacamole user. Once both the Guacamole
+ * audio stream and the RDP audio stream are ready, an appropriate "ack"
+ * message will be sent.
+ *
+ * @param audio_buffer
+ *     The audio buffer associated with the audio stream just received.
+ *
+ * @param user
+ *     The Guacamole user that created the audio stream.
+ *
+ * @param stream
+ *     The guac_stream object representing the audio stream.
+ */
+void guac_rdp_audio_buffer_set_stream(guac_rdp_audio_buffer* audio_buffer,
+        guac_user* user, guac_stream* stream);
+
+/**
  * Begins handling of audio data received via guac_rdp_audio_buffer_write() and
  * allocates the necessary underlying packet buffer. Audio packets of exactly
  * packet_size bytes will be flushed as available using the provided


[17/26] incubator-guacamole-server git commit: GUACAMOLE-25: Support FreeRDP stable-1.0 and compatible.

Posted by jm...@apache.org.
GUACAMOLE-25: Support FreeRDP stable-1.0 and compatible.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/8ccf61e6
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/8ccf61e6
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/8ccf61e6

Branch: refs/heads/master
Commit: 8ccf61e6b1d9198b073b17f5bafe96e12ca65c06
Parents: f1d4393
Author: Michael Jumper <mj...@apache.org>
Authored: Mon May 9 22:23:46 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 13:50:29 2016 -0700

----------------------------------------------------------------------
 configure.ac                           |  9 ++++++++
 src/protocols/rdp/dvc.c                | 33 +++++++++++++++++++++++++++--
 src/protocols/rdp/guac_ai/ai_service.c |  6 ++++++
 3 files changed, 46 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/8ccf61e6/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 7dec629..446a36e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -579,6 +579,15 @@ then
         [#include <freerdp/channels/channels.h>])
 fi
 
+# Availability of ADDIN_ARGV structure for configuring plugins
+if test "x${have_freerdp}" = "xyes"
+then
+    AC_CHECK_TYPE([ADDIN_ARGV],
+        [AC_DEFINE([HAVE_ADDIN_ARGV],,
+                   [Whether the ADDIN_ARGV type is available])],,
+        [#include <freerdp/settings.h>])
+fi
+
 #
 # FreeRDP: WinPR
 #

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/8ccf61e6/src/protocols/rdp/dvc.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/dvc.c b/src/protocols/rdp/dvc.c
index 0f0e835..10c65d7 100644
--- a/src/protocols/rdp/dvc.c
+++ b/src/protocols/rdp/dvc.c
@@ -117,6 +117,14 @@ int guac_rdp_load_drdynvc(rdpContext* context, guac_rdp_dvc_list* list) {
     if (list->channel_count == 0)
         return 0;
 
+#ifndef HAVE_ADDIN_ARGV
+    /* Allocate plugin data array */
+    RDP_PLUGIN_DATA* all_plugin_data =
+        calloc(list->channel_count + 1, sizeof(RDP_PLUGIN_DATA));
+
+    RDP_PLUGIN_DATA* current_plugin_data = all_plugin_data;
+#endif
+
     /* For each channel */
     guac_common_list_element* current = list->channels->head;
     while (current != NULL) {
@@ -135,20 +143,41 @@ int guac_rdp_load_drdynvc(rdpContext* context, guac_rdp_dvc_list* list) {
         guac_client_log(client, GUAC_LOG_DEBUG,
                 "Registering DVC plugin \"%s\"", dvc->argv[0]);
 
+#ifdef HAVE_ADDIN_ARGV
         /* Register plugin with FreeRDP */
         ADDIN_ARGV* args = malloc(sizeof(ADDIN_ARGV));
         args->argc = dvc->argc;
         args->argv = dvc->argv;
         freerdp_dynamic_channel_collection_add(context->settings, args);
+#else
+        /* Copy all arguments */
+        for (int i = 0; i < dvc->argc; i++)
+            current_plugin_data->data[i] = dvc->argv[i];
+
+        /* Store size of entry */
+        current_plugin_data->size = sizeof(*current_plugin_data);
+
+        /* Advance to next set of plugin data */
+        current_plugin_data++;
+#endif
 
         /* Rely on FreeRDP to free argv storage */
         dvc->argv = NULL;
 
     }
 
+#ifdef HAVE_ADDIN_ARGV
+    /* Load virtual channel management plugin */
+    return freerdp_channels_load_plugin(channels, context->instance->settings,
+                "drdynvc", context->instance->settings);
+#else
+    /* Terminate with empty RDP_PLUGIN_DATA element */
+    current_plugin_data->size = 0;
+
     /* Load virtual channel management plugin */
-    return freerdp_channels_load_plugin(channels, context->settings,
-                "drdynvc", context->settings);
+    return freerdp_channels_load_plugin(channels, context->instance->settings,
+                "drdynvc", all_plugin_data);
+#endif
 
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/8ccf61e6/src/protocols/rdp/guac_ai/ai_service.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/guac_ai/ai_service.c b/src/protocols/rdp/guac_ai/ai_service.c
index 2fbf2ac..5058ea0 100644
--- a/src/protocols/rdp/guac_ai/ai_service.c
+++ b/src/protocols/rdp/guac_ai/ai_service.c
@@ -314,8 +314,14 @@ static int guac_rdp_ai_terminated(IWTSPlugin* plugin) {
  */
 int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) {
 
+    /* Pull guac_client from arguments */
+#ifdef HAVE_ADDIN_ARGV
     ADDIN_ARGV* args = pEntryPoints->GetPluginData(pEntryPoints);
     guac_client* client = (guac_client*) guac_rdp_string_to_ptr(args->argv[1]);
+#else
+    RDP_PLUGIN_DATA* data = pEntryPoints->GetPluginData(pEntryPoints);
+    guac_client* client = (guac_client*) guac_rdp_string_to_ptr(data->data[1]);
+#endif
 
     /* Pull previously-allocated plugin */
     guac_rdp_ai_plugin* ai_plugin = (guac_rdp_ai_plugin*)


[05/26] incubator-guacamole-server git commit: GUACAMOLE-25: Convert guac_client pointer to/from a string for sake of FreeRDP's DVC API.

Posted by jm...@apache.org.
GUACAMOLE-25: Convert guac_client pointer to/from a string for sake of FreeRDP's DVC API.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/36cc9f49
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/36cc9f49
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/36cc9f49

Branch: refs/heads/master
Commit: 36cc9f492fb0424d32aaa041383d8e8ab8e3cd90
Parents: 21ab9d7
Author: Michael Jumper <mj...@apache.org>
Authored: Sat Apr 16 17:13:39 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 13:50:28 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/Makefile.am          |  5 ++-
 src/protocols/rdp/audio_input.c        |  5 +++
 src/protocols/rdp/guac_ai/ai_service.c |  7 ++--
 src/protocols/rdp/ptr_string.c         | 55 ++++++++++++++++++++++++++++
 src/protocols/rdp/ptr_string.h         | 57 +++++++++++++++++++++++++++++
 5 files changed, 124 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/36cc9f49/src/protocols/rdp/Makefile.am
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/Makefile.am b/src/protocols/rdp/Makefile.am
index 44f248a..0ac074a 100644
--- a/src/protocols/rdp/Makefile.am
+++ b/src/protocols/rdp/Makefile.am
@@ -27,6 +27,7 @@ libguac_client_rdp_la_SOURCES = \
     audio_input.c               \
     client.c                    \
     input.c                     \
+    ptr_string.c                \
     rdp.c                       \
     rdp_bitmap.c                \
     rdp_cliprdr.c               \
@@ -46,7 +47,8 @@ libguac_client_rdp_la_SOURCES = \
     user.c
 
 guacai_sources =         \
-    guac_ai/ai_service.c
+    guac_ai/ai_service.c \
+	ptr_string.c
 
 guacsvc_sources =          \
     guac_svc/svc_service.c \
@@ -87,6 +89,7 @@ noinst_HEADERS =                             \
     audio_input.h                            \
     client.h                                 \
     input.h                                  \
+    ptr_string.h                             \
     rdp.h                                    \
     rdp_bitmap.h                             \
     rdp_cliprdr.h                            \

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/36cc9f49/src/protocols/rdp/audio_input.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.c b/src/protocols/rdp/audio_input.c
index 8233184..b5c3f96 100644
--- a/src/protocols/rdp/audio_input.c
+++ b/src/protocols/rdp/audio_input.c
@@ -19,6 +19,8 @@
 
 #include "config.h"
 #include "audio_input.h"
+#include "ptr_string.h"
+#include "rdp.h"
 
 #include <freerdp/freerdp.h>
 #include <freerdp/channels/channels.h>
@@ -63,11 +65,14 @@ int guac_rdp_audio_end_handler(guac_user* user, guac_stream* stream) {
 
 void guac_rdp_audio_load_plugin(rdpContext* context) {
 
+    guac_client* client = ((rdp_freerdp_context*) context)->client;
+
     /* Add "AUDIO_INPUT" channel */
     ADDIN_ARGV* args = malloc(sizeof(ADDIN_ARGV));
     args->argc = 1;
     args->argv = malloc(sizeof(char**) * 1);
     args->argv[0] = strdup("guacai");
+    args->argv[1] = guac_rdp_ptr_to_string(client);
     freerdp_dynamic_channel_collection_add(context->settings, args);
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/36cc9f49/src/protocols/rdp/guac_ai/ai_service.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/guac_ai/ai_service.c b/src/protocols/rdp/guac_ai/ai_service.c
index 15490a0..c6ff47b 100644
--- a/src/protocols/rdp/guac_ai/ai_service.c
+++ b/src/protocols/rdp/guac_ai/ai_service.c
@@ -20,6 +20,7 @@
 #include "config.h"
 
 #include "ai_service.h"
+#include "ptr_string.h"
 #include "rdp.h"
 
 #include <stdlib.h>
@@ -41,10 +42,8 @@
  */
 int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) {
 
-    rdpSettings* settings = pEntryPoints->GetRdpSettings(pEntryPoints);
-    freerdp* instance = settings->instance;
-    rdpContext* context = instance->context;
-    guac_client* client = ((rdp_freerdp_context*) context)->client;
+    ADDIN_ARGV* args = pEntryPoints->GetPluginData(pEntryPoints);
+    guac_client* client = (guac_client*) guac_rdp_string_to_ptr(args->argv[1]);
 
     /* STUB */
     guac_client_log(client, GUAC_LOG_DEBUG,

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/36cc9f49/src/protocols/rdp/ptr_string.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/ptr_string.c b/src/protocols/rdp/ptr_string.c
new file mode 100644
index 0000000..1e79121
--- /dev/null
+++ b/src/protocols/rdp/ptr_string.c
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "config.h"
+#include "ptr_string.h"
+
+#include <guacamole/client.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/**
+ * The maximum number of bytes required to represent a pointer printed using
+ * printf()'s "%p". This will be the size of the hex prefix ("0x"), null
+ * terminator, plus two bytes for every byte required by a pointer.
+ */
+#define GUAC_RDP_PTR_STRING_LENGTH (sizeof("0x") + (sizeof(void*) * 2))
+
+char* guac_rdp_ptr_to_string(void* data) {
+
+    /* Convert pointer to string */
+    char* str = malloc(GUAC_RDP_PTR_STRING_LENGTH);
+    sprintf(str, "%p", data);
+
+    return str;
+
+}
+
+void* guac_rdp_string_to_ptr(const char* str) {
+
+    void* data;
+
+    /* Convert string to pointer */
+    sscanf(str, "%p", &data);
+
+    return data;
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/36cc9f49/src/protocols/rdp/ptr_string.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/ptr_string.h b/src/protocols/rdp/ptr_string.h
new file mode 100644
index 0000000..6b27721
--- /dev/null
+++ b/src/protocols/rdp/ptr_string.h
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 GUAC_RDP_PTR_STRING_H
+#define GUAC_RDP_PTR_STRING_H
+
+#include "config.h"
+
+#include <guacamole/client.h>
+
+/**
+ * Converts the given string back into a void pointer. The string MUST have
+ * been produced via guac_rdp_ptr_to_string().
+ *
+ * @param str
+ *     The string to convert back to a pointer.
+ *
+ * @return
+ *     The pointer value of the given string, as originally passed to
+ *     guac_rdp_ptr_to_string().
+ */
+void* guac_rdp_string_to_ptr(const char* str);
+
+/**
+ * Converts a void pointer into a string representation, safe for use with
+ * parts of the FreeRDP API which provide only for passing arbitrary strings,
+ * despite being within the same memory area. The returned string must
+ * eventually be freed with a call to free().
+ *
+ * @param data
+ *     The void pointer to convert to a string.
+ *
+ * @return
+ *     A newly-allocated string containing the string representation of the
+ *     given void pointer. This string must eventually be freed with a call to
+ *     free().
+ */
+char* guac_rdp_ptr_to_string(void* data);
+
+#endif
+


[23/26] incubator-guacamole-server git commit: GUACAMOLE-25: Resample received audio as necessary.

Posted by jm...@apache.org.
GUACAMOLE-25: Resample received audio as necessary.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/0be04ea5
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/0be04ea5
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/0be04ea5

Branch: refs/heads/master
Commit: 0be04ea54d0ce8dea9c57d29da15249b7c2db1f3
Parents: 1c2890b
Author: Michael Jumper <mj...@apache.org>
Authored: Wed Jun 1 15:25:42 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Jun 1 15:25:42 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/audio_input.c | 131 ++++++++++++++++++++++++++++++-----
 src/protocols/rdp/audio_input.h |  12 ++++
 2 files changed, 126 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/0be04ea5/src/protocols/rdp/audio_input.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.c b/src/protocols/rdp/audio_input.c
index 0eb757d..eefb231 100644
--- a/src/protocols/rdp/audio_input.c
+++ b/src/protocols/rdp/audio_input.c
@@ -30,6 +30,7 @@
 #include <guacamole/stream.h>
 #include <guacamole/user.h>
 
+#include <assert.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <pthread.h>
@@ -246,6 +247,9 @@ void guac_rdp_audio_buffer_set_stream(guac_rdp_audio_buffer* audio_buffer,
     audio_buffer->in_format.channels = channels;
     audio_buffer->in_format.bps = bps;
 
+    /* Reset input counter */
+    audio_buffer->total_bytes_received = 0;
+
     /* Acknowledge stream creation (if buffer is ready to receive) */
     guac_rdp_audio_buffer_ack(audio_buffer,
             "OK", GUAC_PROTOCOL_STATUS_SUCCESS);
@@ -270,6 +274,9 @@ void guac_rdp_audio_buffer_set_output(guac_rdp_audio_buffer* audio_buffer,
     audio_buffer->out_format.channels = channels;
     audio_buffer->out_format.bps = bps;
 
+    /* Reset output counter */
+    audio_buffer->total_bytes_sent = 0;
+
     pthread_mutex_unlock(&(audio_buffer->lock));
 
 }
@@ -302,12 +309,99 @@ void guac_rdp_audio_buffer_begin(guac_rdp_audio_buffer* audio_buffer,
 
 }
 
+/**
+ * Reads a single sample from the given buffer of data, using the input
+ * format defined within the given audio buffer. Each read sample is
+ * translated to a signed 16-bit value, even if the input format is 8-bit.
+ * The offset into the given buffer will be determined according to the
+ * input and output formats, the number of bytes sent thus far, and the
+ * number of bytes received (excluding the contents of the buffer).
+ *
+ * @param audio_buffer
+ *     The audio buffer dictating the format of the given data buffer, as
+ *     well as the offset from which the sample should be read.
+ *
+ * @param buffer
+ *     The buffer of raw PCM audio data from which the sample should be read.
+ *     This buffer MUST NOT contain data already taken into account by the
+ *     audio buffer's total_bytes_received counter.
+ *
+ * @param length
+ *     The number of bytes within the given buffer of PCM data.
+ *
+ * @param sample
+ *     A pointer to the int16_t in which the read sample should be stored. If
+ *     the input format is 8-bit, the sample will be shifted left by 8 bits
+ *     to produce a 16-bit sample.
+ *
+ * @return
+ *     Non-zero if a sample was successfully read, zero if no data remains
+ *     within the given buffer that has not already been mapped to an
+ *     output sample.
+ */
+static int guac_rdp_audio_buffer_read_sample(
+        guac_rdp_audio_buffer* audio_buffer, const char* buffer, int length,
+        int16_t* sample) {
+
+    int in_bps = audio_buffer->in_format.bps;
+    int in_rate = audio_buffer->in_format.rate;
+    int in_channels = audio_buffer->in_format.channels;
+
+    int out_bps = audio_buffer->out_format.bps;
+    int out_rate = audio_buffer->out_format.rate;
+    int out_channels = audio_buffer->out_format.channels;
+
+    /* Calculate position within audio output */
+    int current_sample  = audio_buffer->total_bytes_sent / out_bps;
+    int current_frame   = current_sample / out_channels;
+    int current_channel = current_sample % out_channels;
+
+    /* Map output channel to input channel */
+    if (current_channel >= in_channels)
+        current_channel = in_channels - 1;
+
+    /* Transform output position to input position */
+    current_frame = (int) current_frame * ((double) in_rate / out_rate);
+    current_sample = current_frame * in_channels + current_channel;
+
+    /* Calculate offset within given buffer from absolute input position */
+    int offset = current_sample * in_bps
+               - audio_buffer->total_bytes_received;
+
+    /* It should be impossible for the offset to ever go negative */
+    assert(offset >= 0);
+
+    /* Apply offset to buffer */
+    buffer += offset;
+    length -= offset;
+
+    /* Read only if sufficient data is present in the given buffer */
+    if (length < in_bps)
+        return 0;
+
+    /* Simply read sample directly if input is 16-bit */
+    if (in_bps == 2) {
+        *sample = *((int16_t*) buffer);
+        return 1;
+    }
+
+    /* Translate to 16-bit if input is 8-bit */
+    if (in_bps == 1) {
+        *sample = *buffer << 8;
+        return 1;
+    }
+
+    /* Accepted audio formats are required to be 8- or 16-bit */
+    return 0;
+
+}
+
 void guac_rdp_audio_buffer_write(guac_rdp_audio_buffer* audio_buffer,
         char* buffer, int length) {
 
-    pthread_mutex_lock(&(audio_buffer->lock));
+    int16_t sample;
 
-    /* FIXME: Assuming mimetype of "audio/L16;rate=44100,channels=2" */
+    pthread_mutex_lock(&(audio_buffer->lock));
 
     /* Ignore packet if there is no buffer */
     if (audio_buffer->packet_size == 0 || audio_buffer->packet == NULL) {
@@ -315,27 +409,27 @@ void guac_rdp_audio_buffer_write(guac_rdp_audio_buffer* audio_buffer,
         return;
     }
 
+    int out_bps = audio_buffer->out_format.bps;
+
     /* Continuously write packets until no data remains */
-    while (length > 0) {
+    while (guac_rdp_audio_buffer_read_sample(audio_buffer,
+                buffer, length, &sample) > 0) {
 
-        /* Calculate ideal size of chunk based on available space */
-        int chunk_size = audio_buffer->packet_size
-                       - audio_buffer->bytes_written;
+        char* current = audio_buffer->packet + audio_buffer->bytes_written;
 
-        /* Shrink chunk size if insufficient bytes are provided */
-        if (length < chunk_size)
-            chunk_size = length;
+        /* Store as 16-bit or 8-bit, depending on output format */
+        if (out_bps == 2)
+            *((int16_t*) current) = sample;
+        else if (out_bps == 1)
+            *current = sample >> 8;
 
-        /* Append buffer */
-        memcpy(audio_buffer->packet + audio_buffer->bytes_written,
-                buffer, chunk_size);
+        /* Accepted audio formats are required to be 8- or 16-bit */
+        else
+            assert(0);
 
         /* Update byte counters */
-        length -= chunk_size;
-        audio_buffer->bytes_written += chunk_size;
-
-        /* Advance to next chunk */
-        buffer += chunk_size;
+        audio_buffer->bytes_written += out_bps;
+        audio_buffer->total_bytes_sent += out_bps;
 
         /* Invoke flush handler if full */
         if (audio_buffer->bytes_written == audio_buffer->packet_size) {
@@ -352,6 +446,9 @@ void guac_rdp_audio_buffer_write(guac_rdp_audio_buffer* audio_buffer,
 
     } /* end packet write loop */
 
+    /* Track current position in audio stream */
+    audio_buffer->total_bytes_received += length;
+
     pthread_mutex_unlock(&(audio_buffer->lock));
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/0be04ea5/src/protocols/rdp/audio_input.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.h b/src/protocols/rdp/audio_input.h
index 87eee9a..bd84fe1 100644
--- a/src/protocols/rdp/audio_input.h
+++ b/src/protocols/rdp/audio_input.h
@@ -122,6 +122,18 @@ typedef struct guac_rdp_audio_buffer {
     int bytes_written;
 
     /**
+     * The total number of bytes having ever been received by the Guacamole
+     * server for the current audio stream.
+     */
+    int total_bytes_received;
+
+    /**
+     * The total number of bytes having ever been sent to the RDP server for
+     * the current audio stream.
+     */
+    int total_bytes_sent;
+
+    /**
      * All audio data being prepared for sending to the AUDIO_INPUT channel.
      */
     char* packet;


[09/26] incubator-guacamole-server git commit: GUACAMOLE-25: Set AudioCapture flag if audio input is enabled.

Posted by jm...@apache.org.
GUACAMOLE-25: Set AudioCapture flag if audio input is enabled.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/4fdcfebf
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/4fdcfebf
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/4fdcfebf

Branch: refs/heads/master
Commit: 4fdcfebf2548161d771e430bead6ce7c29a3fc98
Parents: 36cc9f4
Author: Michael Jumper <mj...@apache.org>
Authored: Sat Apr 16 21:42:31 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 13:50:28 2016 -0700

----------------------------------------------------------------------
 configure.ac                     | 12 ++++++++++++
 src/protocols/rdp/rdp_settings.c | 11 +++++++++++
 2 files changed, 23 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/4fdcfebf/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index edd49b8..485c10d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -436,6 +436,7 @@ then
     have_freerdp=yes
     legacy_freerdp_extensions=no
     rdpsettings_interface=unknown
+    rdpsettings_audiocapture=yes
     rdpsettings_audioplayback=yes
     rdpsettings_deviceredirection=yes
     freerdp_interface=unknown
@@ -686,6 +687,11 @@ then
                          [rdpsettings_audioplayback=no],
                          [[#include <freerdp/freerdp.h>]])
 
+        # Legacy interface may not have AudioCapture settings
+        AC_CHECK_MEMBERS([rdpSettings.audio_capture],,
+                         [rdpsettings_audiocapture=no],
+                         [[#include <freerdp/freerdp.h>]])
+
         # Legacy interface may not have DeviceRedirection settings
         AC_CHECK_MEMBERS([rdpSettings.device_redirection],,
                          [rdpsettings_deviceredirection=no],
@@ -707,6 +713,12 @@ if test "x${have_freerdp}" = "xyes" -a "x${rdpsettings_audioplayback}" = "xyes";
               [Whether the rdpSettings structure has AudioPlayback settings])
 fi
 
+# Activate audio capture settings if present
+if test "x${have_freerdp}" = "xyes" -a "x${rdpsettings_audiocapture}" = "xyes"; then
+    AC_DEFINE([HAVE_RDPSETTINGS_AUDIOCAPTURE],,
+              [Whether the rdpSettings structure has AudioCapture settings])
+fi
+
 # Activate device redirection settings if present
 if test "x${have_freerdp}" = "xyes" -a "x${rdpsettings_deviceredirection}" = "xyes"; then
     AC_DEFINE([HAVE_RDPSETTINGS_DEVICEREDIRECTION],,

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/4fdcfebf/src/protocols/rdp/rdp_settings.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/rdp_settings.c b/src/protocols/rdp/rdp_settings.c
index 4f9343c..82af859 100644
--- a/src/protocols/rdp/rdp_settings.c
+++ b/src/protocols/rdp/rdp_settings.c
@@ -995,6 +995,17 @@ void guac_rdp_push_settings(guac_rdp_settings* guac_settings, freerdp* rdp) {
 #endif
 #endif
 
+    /* Audio capture */
+#ifdef LEGACY_RDPSETTINGS
+#ifdef HAVE_RDPSETTINGS_AUDIOCAPTURE
+    rdp_settings->audio_capture = guac_settings->enable_audio_input;
+#endif
+#else
+#ifdef HAVE_RDPSETTINGS_AUDIOCAPTURE
+    rdp_settings->AudioCapture = guac_settings->enable_audio_input;
+#endif
+#endif
+
     /* Device redirection */
 #ifdef LEGACY_RDPSETTINGS
 #ifdef HAVE_RDPSETTINGS_DEVICEREDIRECTION


[02/26] incubator-guacamole-server git commit: GUACAMOLE-25: Abstract DVC management away from FreeRDP for sake of API compatibility.

Posted by jm...@apache.org.
GUACAMOLE-25: Abstract DVC management away from FreeRDP for sake of API compatibility.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/13933584
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/13933584
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/13933584

Branch: refs/heads/master
Commit: 13933584691f20c7d88294ac41aa6dd4c4f8bf04
Parents: 46bdf06
Author: Michael Jumper <mj...@apache.org>
Authored: Mon May 9 18:20:04 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 13:50:28 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/Makefile.am   |   2 +
 src/protocols/rdp/audio_input.c |  10 +--
 src/protocols/rdp/audio_input.h |   3 +-
 src/protocols/rdp/dvc.c         | 154 +++++++++++++++++++++++++++++++++++
 src/protocols/rdp/dvc.h         | 138 +++++++++++++++++++++++++++++++
 src/protocols/rdp/rdp.c         |  44 +++++-----
 src/protocols/rdp/rdp_disp.c    |  11 +--
 src/protocols/rdp/rdp_disp.h    |   3 +-
 8 files changed, 323 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/13933584/src/protocols/rdp/Makefile.am
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/Makefile.am b/src/protocols/rdp/Makefile.am
index f76c33e..3669b3d 100644
--- a/src/protocols/rdp/Makefile.am
+++ b/src/protocols/rdp/Makefile.am
@@ -26,6 +26,7 @@ libguac_client_rdp_la_SOURCES = \
     _generated_keymaps.c        \
     audio_input.c               \
     client.c                    \
+    dvc.c                       \
     input.c                     \
     ptr_string.c                \
     rdp.c                       \
@@ -91,6 +92,7 @@ noinst_HEADERS =                             \
     guac_svc/svc_service.h                   \
     audio_input.h                            \
     client.h                                 \
+    dvc.h                                    \
     input.h                                  \
     ptr_string.h                             \
     rdp.h                                    \

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/13933584/src/protocols/rdp/audio_input.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.c b/src/protocols/rdp/audio_input.c
index 93c492b..f2fd84a 100644
--- a/src/protocols/rdp/audio_input.c
+++ b/src/protocols/rdp/audio_input.c
@@ -19,6 +19,7 @@
 
 #include "config.h"
 #include "audio_input.h"
+#include "dvc.h"
 #include "ptr_string.h"
 #include "rdp.h"
 
@@ -71,17 +72,12 @@ int guac_rdp_audio_end_handler(guac_user* user, guac_stream* stream) {
 
 }
 
-void guac_rdp_audio_load_plugin(rdpContext* context) {
+void guac_rdp_audio_load_plugin(rdpContext* context, guac_rdp_dvc_list* list) {
 
     guac_client* client = ((rdp_freerdp_context*) context)->client;
 
     /* Add "AUDIO_INPUT" channel */
-    ADDIN_ARGV* args = malloc(sizeof(ADDIN_ARGV));
-    args->argc = 2;
-    args->argv = malloc(sizeof(char**) * 2);
-    args->argv[0] = strdup("guacai");
-    args->argv[1] = guac_rdp_ptr_to_string(client);
-    freerdp_dynamic_channel_collection_add(context->settings, args);
+    guac_rdp_dvc_list_add(list, "guacai", guac_rdp_ptr_to_string(client), NULL);
 
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/13933584/src/protocols/rdp/audio_input.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.h b/src/protocols/rdp/audio_input.h
index 776f0a5..e13b41e 100644
--- a/src/protocols/rdp/audio_input.h
+++ b/src/protocols/rdp/audio_input.h
@@ -21,6 +21,7 @@
 #define GUAC_RDP_AUDIO_INPUT_H
 
 #include "config.h"
+#include "dvc.h"
 
 #include <freerdp/freerdp.h>
 #include <guacamole/stream.h>
@@ -213,7 +214,7 @@ guac_user_end_handler guac_rdp_audio_end_handler;
  * @param context
  *     The rdpContext associated with the active RDP session.
  */
-void guac_rdp_audio_load_plugin(rdpContext* context);
+void guac_rdp_audio_load_plugin(rdpContext* context, guac_rdp_dvc_list* list);
 
 #endif
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/13933584/src/protocols/rdp/dvc.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/dvc.c b/src/protocols/rdp/dvc.c
new file mode 100644
index 0000000..0f0e835
--- /dev/null
+++ b/src/protocols/rdp/dvc.c
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "config.h"
+#include "dvc.h"
+#include "guac_list.h"
+#include "rdp.h"
+
+#include <freerdp/channels/channels.h>
+#include <freerdp/freerdp.h>
+#include <guacamole/client.h>
+
+#include <assert.h>
+#include <stdarg.h>
+
+guac_rdp_dvc_list* guac_rdp_dvc_list_alloc() {
+
+    guac_rdp_dvc_list* list = malloc(sizeof(guac_rdp_dvc_list));
+
+    /* Initialize with empty backing list */
+    list->channels = guac_common_list_alloc();
+    list->channel_count = 0;
+
+    return list;
+
+}
+
+void guac_rdp_dvc_list_add(guac_rdp_dvc_list* list, const char* name, ...) {
+
+    va_list args;
+
+    guac_rdp_dvc* dvc = malloc(sizeof(guac_rdp_dvc));
+
+    va_start(args, name);
+
+    /* Count number of arguments (excluding terminating NULL) */
+    dvc->argc = 1;
+    while (va_arg(args, char*) != NULL)
+        dvc->argc++;
+
+    /* Reset va_list */
+    va_end(args);
+    va_start(args, name);
+
+    /* Copy argument values into DVC entry */
+    dvc->argv = malloc(sizeof(char*) * dvc->argc);
+    dvc->argv[0] = strdup(name);
+    int i;
+    for (i = 1; i < dvc->argc; i++)
+        dvc->argv[i] = strdup(va_arg(args, char*));
+
+    va_end(args);
+
+    /* Add entry to DVC list */
+    guac_common_list_add(list->channels, dvc);
+
+    /* Update channel count */
+    list->channel_count++;
+
+}
+
+void guac_rdp_dvc_list_free(guac_rdp_dvc_list* list) {
+
+    /* For each channel */
+    guac_common_list_element* current = list->channels->head;
+    while (current != NULL) {
+
+        /* Free arguments declaration for current channel */
+        guac_rdp_dvc* dvc = (guac_rdp_dvc*) current->data;
+
+        /* Free the underlying arguments list if not delegated to FreeRDP */
+        if (dvc->argv != NULL) {
+
+            /* Free each argument value */
+            for (int i = 0; i < dvc->argc; i++)
+                free(dvc->argv[i]);
+
+            free(dvc->argv);
+        }
+
+        free(dvc);
+
+        current = current->next;
+
+    }
+
+    /* Free underlying list */
+    guac_common_list_free(list->channels);
+
+    /* Free the DVC list itself */
+    free(list);
+
+}
+
+int guac_rdp_load_drdynvc(rdpContext* context, guac_rdp_dvc_list* list) {
+
+    guac_client* client = ((rdp_freerdp_context*) context)->client;
+    rdpChannels* channels = context->channels;
+
+    /* Skip if no channels will be loaded */
+    if (list->channel_count == 0)
+        return 0;
+
+    /* For each channel */
+    guac_common_list_element* current = list->channels->head;
+    while (current != NULL) {
+
+        /* Get channel arguments */
+        guac_rdp_dvc* dvc = (guac_rdp_dvc*) current->data;
+        current = current->next;
+
+        /* guac_rdp_dvc_list_add() guarantees at one argument */
+        assert(dvc->argc >= 1);
+
+        /* guac_rdp_load_drdynvc() MUST only be invoked once */
+        assert(dvc->argv != NULL);
+
+        /* Log registration of plugin for current channel */
+        guac_client_log(client, GUAC_LOG_DEBUG,
+                "Registering DVC plugin \"%s\"", dvc->argv[0]);
+
+        /* Register plugin with FreeRDP */
+        ADDIN_ARGV* args = malloc(sizeof(ADDIN_ARGV));
+        args->argc = dvc->argc;
+        args->argv = dvc->argv;
+        freerdp_dynamic_channel_collection_add(context->settings, args);
+
+        /* Rely on FreeRDP to free argv storage */
+        dvc->argv = NULL;
+
+    }
+
+    /* Load virtual channel management plugin */
+    return freerdp_channels_load_plugin(channels, context->settings,
+                "drdynvc", context->settings);
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/13933584/src/protocols/rdp/dvc.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/dvc.h b/src/protocols/rdp/dvc.h
new file mode 100644
index 0000000..02ca643
--- /dev/null
+++ b/src/protocols/rdp/dvc.h
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 GUAC_RDP_DVC_H
+#define GUAC_RDP_DVC_H
+
+#include "config.h"
+#include "guac_list.h"
+
+#include <freerdp/freerdp.h>
+
+/**
+ * The set of all arguments that should be passed to a given dynamic virtual
+ * channel plugin, including the name of that plugin.
+ */
+typedef struct guac_rdp_dvc {
+
+    /**
+     * The number of arguments in the argv array. This MUST be at least 1.
+     */
+    int argc;
+
+    /**
+     * The argument values being passed to the dynamic virtual channel plugin.
+     * The first entry in this array is always the name of the plugin. If
+     * guac_rdp_load_drdynvc() has been invoked, and freeing the argument
+     * values is being delegated to FreeRDP, this will be NULL.
+     */
+    char** argv;
+
+} guac_rdp_dvc;
+
+/**
+ * A list of dynamic virtual channels which should be provided to the DRDYNVC
+ * plugin once loaded via guac_rdp_load_drdynvc(). This interface exists purely
+ * to bridge incompatibilities between differing versions of FreeRDP and its
+ * DRDYNVC plugin. Any allocated guac_rdp_dvc_list is unlikely to be needed
+ * after the DRDYNVC plugin has been loaded.
+ */
+typedef struct guac_rdp_dvc_list {
+
+    /**
+     * Array of all dynamic virtual channels which should be registered with
+     * the DRDYNVC plugin once loaded. Each list element will point to a
+     * guac_rdp_dvc structure which must eventually be freed.
+     */
+    guac_common_list* channels;
+
+    /**
+     * The number of channels within the list.
+     */
+    int channel_count;
+
+} guac_rdp_dvc_list;
+
+/**
+ * Allocates a new, empty list of dynamic virtual channels. New channels may
+ * be added via guac_rdp_dvc_list_add(). The loading of those channels'
+ * associated plugins will be deferred until guac_rdp_load_drdynvc() is
+ * invoked.
+ *
+ * @return
+ *     A newly-allocated, empty list of dynamic virtual channels.
+ */
+guac_rdp_dvc_list* guac_rdp_dvc_list_alloc();
+
+/**
+ * Adds the given dynamic virtual channel plugin name and associated arguments
+ * to the list. The provied arguments list is NOT optional and MUST be
+ * NULL-terminated, even if there are no arguments for the named dynamic
+ * virtual channel plugin. Though FreeRDP requires that the arguments for a
+ * dynamic virtual channel plugin contain the name of the plugin itself as the
+ * first argument, the name must be excluded from the arguments provided here.
+ * This function will automatically take care of adding the plugin name to
+ * the arguments.
+ *
+ * @param list
+ *     The guac_rdp_dvc_list to which the given plugin name and arguments
+ *     should be added, for later bulk registration via
+ *     guac_rdp_load_drdynvc().
+ *
+ * @param name
+ *     The name of the dynamic virtual channel plugin that should be given
+ *     the provided arguments when guac_rdp_load_drdynvc() is invoked.
+ *
+ * @param ...
+ *     The string (char*) arguments which should be passed to the dynamic
+ *     virtual channel plugin when it is loaded via guac_rdp_load_drdynvc(),
+ *     excluding the plugin name itself.
+ */
+void guac_rdp_dvc_list_add(guac_rdp_dvc_list* list, const char* name, ...);
+
+/**
+ * Frees the given list of dynamic virtual channels. Note that, while each
+ * individual entry within this list will be freed, it is partially up to
+ * FreeRDP to free the storage associated with the arguments passed to the
+ * virtual channels.
+ *
+ * @param list
+ *     The list to free.
+ */
+void guac_rdp_dvc_list_free(guac_rdp_dvc_list* list);
+
+/**
+ * Loads FreeRDP's DRDYNVC plugin and registers the dynamic virtual channel
+ * plugins described by the given guac_rdp_dvc_list. This function MUST be
+ * invoked no more than once per RDP connection. Invoking this function
+ * multiple times, even if the guac_rdp_dvc_list is different each time, will
+ * result in undefined behavior.
+ *
+ * @param context
+ *     The rdpContext associated with the RDP connection for which the DRDYNVC
+ *     plugin should be loaded.
+ *
+ * @param list
+ *     A guac_rdp_dvc_list describing the dynamic virtual channel plugins that
+ *     should be registered with the DRDYNVC plugin, along with any arguments.
+ */
+int guac_rdp_load_drdynvc(rdpContext* context, guac_rdp_dvc_list* list);
+
+#endif
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/13933584/src/protocols/rdp/rdp.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c
index f461369..d515fb1 100644
--- a/src/protocols/rdp/rdp.c
+++ b/src/protocols/rdp/rdp.c
@@ -21,6 +21,7 @@
 
 #include "audio_input.h"
 #include "client.h"
+#include "dvc.h"
 #include "guac_cursor.h"
 #include "guac_display.h"
 #include "guac_recording.h"
@@ -212,6 +213,7 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
     rdpPrimaryUpdate* primary;
     CLRCONV* clrconv;
 
+    guac_rdp_dvc_list* dvc_list = guac_rdp_dvc_list_alloc();
 
 #ifdef HAVE_FREERDP_REGISTER_ADDIN_PROVIDER
     /* Init FreeRDP add-in provider */
@@ -224,34 +226,17 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
             (pChannelConnectedEventHandler) guac_rdp_channel_connected);
 #endif
 
-    /* Load DRDYNVC plugin if required */
-    if (settings->resize_method == GUAC_RESIZE_DISPLAY_UPDATE
-            || settings->enable_audio_input) {
-
-        /* Load virtual channel management plugin */
-        if (freerdp_channels_load_plugin(channels, instance->settings,
-                    "drdynvc", instance->settings))
-            guac_client_log(client, GUAC_LOG_WARNING,
-                    "Failed to load drdynvc plugin. Display update and audio "
-                    "input support will be disabled.");
-
-        /* Init display update plugin if "drdynvc" was loaded successfully */
-        else {
 #ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
-            /* Load "disp" plugin for display update */
-            if (settings->resize_method == GUAC_RESIZE_DISPLAY_UPDATE)
-                guac_rdp_disp_load_plugin(instance->context);
+    /* Load "disp" plugin for display update */
+    if (settings->resize_method == GUAC_RESIZE_DISPLAY_UPDATE)
+        guac_rdp_disp_load_plugin(instance->context, dvc_list);
 #endif
 
-            /* Load "AUDIO_INPUT" plugin for audio input*/
-            if (settings->enable_audio_input) {
-                rdp_client->audio_input = guac_rdp_audio_buffer_alloc();
-                guac_rdp_audio_load_plugin(instance->context);
-            }
-
-        }
-
-    } /* end if drdynvc required */
+    /* Load "AUDIO_INPUT" plugin for audio input*/
+    if (settings->enable_audio_input) {
+        rdp_client->audio_input = guac_rdp_audio_buffer_alloc();
+        guac_rdp_audio_load_plugin(instance->context, dvc_list);
+    }
 
     /* Load clipboard plugin */
     if (freerdp_channels_load_plugin(channels, instance->settings,
@@ -338,6 +323,15 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
 
     }
 
+    /* Load DRDYNVC plugin if required */
+    if (guac_rdp_load_drdynvc(instance->context, dvc_list))
+        guac_client_log(client, GUAC_LOG_WARNING,
+                "Failed to load drdynvc plugin. Display update and audio "
+                "input support will be disabled.");
+
+    /* Dynamic virtual channel list is no longer needed */
+    guac_rdp_dvc_list_free(dvc_list);
+
     /* Init color conversion structure */
     clrconv = calloc(1, sizeof(CLRCONV));
     clrconv->alpha = 1;

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/13933584/src/protocols/rdp/rdp_disp.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/rdp_disp.c b/src/protocols/rdp/rdp_disp.c
index eb14286..7c7e059 100644
--- a/src/protocols/rdp/rdp_disp.c
+++ b/src/protocols/rdp/rdp_disp.c
@@ -19,6 +19,7 @@
 
 #include "config.h"
 #include "client.h"
+#include "dvc.h"
 #include "rdp.h"
 #include "rdp_disp.h"
 #include "rdp_settings.h"
@@ -54,20 +55,14 @@ void guac_rdp_disp_free(guac_rdp_disp* disp) {
     free(disp);
 }
 
-void guac_rdp_disp_load_plugin(rdpContext* context) {
+void guac_rdp_disp_load_plugin(rdpContext* context, guac_rdp_dvc_list* list) {
 
-#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
 #ifdef HAVE_RDPSETTINGS_SUPPORTDISPLAYCONTROL
     context->settings->SupportDisplayControl = TRUE;
 #endif
 
     /* Add "disp" channel */
-    ADDIN_ARGV* args = malloc(sizeof(ADDIN_ARGV));
-    args->argc = 1;
-    args->argv = malloc(sizeof(char**) * 1);
-    args->argv[0] = strdup("disp");
-    freerdp_dynamic_channel_collection_add(context->settings, args);
-#endif
+    guac_rdp_dvc_list_add(list, "disp", NULL);
 
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/13933584/src/protocols/rdp/rdp_disp.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/rdp_disp.h b/src/protocols/rdp/rdp_disp.h
index 3378cf7..093e7ed 100644
--- a/src/protocols/rdp/rdp_disp.h
+++ b/src/protocols/rdp/rdp_disp.h
@@ -20,6 +20,7 @@
 #ifndef GUAC_RDP_DISP_H
 #define GUAC_RDP_DISP_H
 
+#include "dvc.h"
 #include "rdp_settings.h"
 
 #include <freerdp/freerdp.h>
@@ -102,7 +103,7 @@ void guac_rdp_disp_free(guac_rdp_disp* disp);
  *
  * @param context The rdpContext associated with the active RDP session.
  */
-void guac_rdp_disp_load_plugin(rdpContext* context);
+void guac_rdp_disp_load_plugin(rdpContext* context, guac_rdp_dvc_list* list);
 
 #ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
 /**


[12/26] incubator-guacamole-server git commit: GUACAMOLE-25: Implement message processing. Stub handlers.

Posted by jm...@apache.org.
GUACAMOLE-25: Implement message processing. Stub handlers.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/503ffb0d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/503ffb0d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/503ffb0d

Branch: refs/heads/master
Commit: 503ffb0d450a8dde8da4faff5fc65551ef4f1376
Parents: 1088332
Author: Michael Jumper <mj...@apache.org>
Authored: Sun Apr 17 01:00:42 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 13:50:28 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/Makefile.am           |   8 +-
 src/protocols/rdp/guac_ai/ai_messages.c |  84 ++++++++++++++
 src/protocols/rdp/guac_ai/ai_messages.h | 157 +++++++++++++++++++++++++++
 src/protocols/rdp/guac_ai/ai_service.c  |  47 +++++++-
 src/protocols/rdp/guac_ai/ai_service.h  |   6 +
 5 files changed, 293 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/503ffb0d/src/protocols/rdp/Makefile.am
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/Makefile.am b/src/protocols/rdp/Makefile.am
index 0ac074a..0d07a74 100644
--- a/src/protocols/rdp/Makefile.am
+++ b/src/protocols/rdp/Makefile.am
@@ -46,9 +46,10 @@ libguac_client_rdp_la_SOURCES = \
     unicode.c                   \
     user.c
 
-guacai_sources =         \
-    guac_ai/ai_service.c \
-	ptr_string.c
+guacai_sources =          \
+    guac_ai/ai_messages.c \
+    guac_ai/ai_service.c  \
+    ptr_string.c
 
 guacsvc_sources =          \
     guac_svc/svc_service.c \
@@ -74,6 +75,7 @@ guacdr_sources =                             \
 noinst_HEADERS =                             \
     compat/client-cliprdr.h                  \
     compat/rail.h                            \
+    guac_ai/ai_messages.h                    \
     guac_ai/ai_service.h                     \
     guac_rdpdr/rdpdr_fs_messages.h           \
     guac_rdpdr/rdpdr_fs_messages_dir_info.h  \

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/503ffb0d/src/protocols/rdp/guac_ai/ai_messages.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/guac_ai/ai_messages.c b/src/protocols/rdp/guac_ai/ai_messages.c
new file mode 100644
index 0000000..c799a44
--- /dev/null
+++ b/src/protocols/rdp/guac_ai/ai_messages.c
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "config.h"
+
+#include "ai_messages.h"
+#include "rdp.h"
+
+#include <stdlib.h>
+
+#include <freerdp/freerdp.h>
+#include <freerdp/constants.h>
+#include <freerdp/dvc.h>
+#include <guacamole/client.h>
+
+#ifdef ENABLE_WINPR
+#include <winpr/stream.h>
+#else
+#include "compat/winpr-stream.h"
+#endif
+
+void guac_rdp_ai_process_version(guac_client* client,
+        IWTSVirtualChannel* channel, wStream* stream) {
+
+    UINT32 version;
+    Stream_Read_UINT32(stream, version);
+
+    /* Warn if server's version number is incorrect */
+    if (version != 1)
+        guac_client_log(client, GUAC_LOG_WARNING,
+                "Server reports AUDIO_INPUT version %i, not 1", version);
+
+    /* Build response version PDU */
+    wStream* response = Stream_New(NULL, 5);
+    Stream_Write_UINT8(response,  GUAC_RDP_MSG_SNDIN_VERSION); /* MessageId */
+    Stream_Write_UINT32(response, 1); /* Version */
+
+    /* Send response */
+    channel->Write(channel, (UINT32) Stream_GetPosition(response),
+            Stream_Buffer(response), NULL);
+    Stream_Free(response, TRUE);
+
+}
+
+void guac_rdp_ai_process_formats(guac_client* client,
+        IWTSVirtualChannel* channel, wStream* stream) {
+
+    /* STUB */
+    guac_client_log(client, GUAC_LOG_DEBUG, "AUDIO_INPUT: formats");
+
+}
+
+void guac_rdp_ai_process_open(guac_client* client,
+        IWTSVirtualChannel* channel, wStream* stream) {
+
+    /* STUB */
+    guac_client_log(client, GUAC_LOG_DEBUG, "AUDIO_INPUT: open");
+
+}
+
+void guac_rdp_ai_process_formatchange(guac_client* client,
+        IWTSVirtualChannel* channel, wStream* stream) {
+
+    /* STUB */
+    guac_client_log(client, GUAC_LOG_DEBUG, "AUDIO_INPUT: formatchange");
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/503ffb0d/src/protocols/rdp/guac_ai/ai_messages.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/guac_ai/ai_messages.h b/src/protocols/rdp/guac_ai/ai_messages.h
new file mode 100644
index 0000000..96282e5
--- /dev/null
+++ b/src/protocols/rdp/guac_ai/ai_messages.h
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 GUAC_RDP_AI_MESSAGES_H
+#define GUAC_RDP_AI_MESSAGES_H
+
+#include "config.h"
+
+#include <freerdp/dvc.h>
+#include <guacamole/client.h>
+
+#ifdef ENABLE_WINPR
+#include <winpr/stream.h>
+#else
+#include "compat/winpr-stream.h"
+#endif
+
+/**
+ * The message ID associated with the AUDIO_INPUT Version PDU. The Version PDU
+ * is sent by both the client and the server to indicate their version of the
+ * AUDIO_INPUT channel protocol (which must always be 1).
+ */
+#define GUAC_RDP_MSG_SNDIN_VERSION 0x01
+
+/**
+ * The message ID associated with the AUDIO_INPUT Sound Formats PDU. The
+ * Sound Formats PDU is sent by the client and the server to indicate the
+ * formats of audio supported.
+ */
+#define GUAC_RDP_MSG_SNDIN_FORMATS 0x02
+
+/**
+ * The message ID associated with the AUDIO_INPUT Open PDU. The Open PDU is
+ * sent by the server to inform the client that the AUDIO_INPUT channel is
+ * now open.
+ */
+#define GUAC_RDP_MSG_SNDIN_OPEN 0x03
+
+/**
+ * The message ID associated with the AUDIO_INPUT Open Reply PDU. The Open
+ * Reply PDU is sent by the client (after sending a Format Change PDU) to
+ * acknowledge that the AUDIO_INPUT channel is open.
+ */
+#define GUAC_RDP_MSG_SNDIN_OPEN_REPLY 0x04
+
+/**
+ * The message ID associated with the AUDIO_INPUT Incoming Data PDU. The
+ * Incoming Data PDU is sent by the client to inform the server of incoming
+ * sound format or audio data.
+ */
+#define GUAC_RDP_MSG_SNDIN_DATA_INCOMING 0x05
+
+/**
+ * The message ID associated with the AUDIO_INPUT Data PDU. The Data PDU is
+ * sent by the client and contains audio data read from the microphone.
+ */
+#define GUAC_RDP_MSG_SNDIN_DATA 0x06
+
+/**
+ * The message ID associated with the AUDIO_INPUT Format Change PDU. The Format
+ * Change PDU is sent by the client to acknowledge the current sound format, or
+ * by the server to request a different sound format.
+ */
+#define GUAC_RDP_MSG_SNDIN_FORMATCHANGE 0x07
+
+/**
+ * Processes a Version PDU received from the RDP server. The Version PDU is
+ * sent by the server to indicate its version of the AUDIO_INPUT channel
+ * protocol (which must always be 1).
+ *
+ * @param client
+ *     The guac_client associated with the current RDP connection.
+ *
+ * @param channel
+ *     The IWTSVirtualChannel instance associated with the connected
+ *     AUDIO_INPUT channel.
+ *
+ * @param stream
+ *     The received PDU, with the read position just after the message ID field
+ *     common to all AUDIO_INPUT PDUs.
+ */
+void guac_rdp_ai_process_version(guac_client* client,
+        IWTSVirtualChannel* channel, wStream* stream);
+
+/**
+ * Processes a Sound Formats PDU received from the RDP server. The Sound
+ * Formats PDU is sent by the server to indicate the formats of audio
+ * supported.
+ *
+ * @param client
+ *     The guac_client associated with the current RDP connection.
+ *
+ * @param channel
+ *     The IWTSVirtualChannel instance associated with the connected
+ *     AUDIO_INPUT channel.
+ *
+ * @param stream
+ *     The received PDU, with the read position just after the message ID field
+ *     common to all AUDIO_INPUT PDUs.
+ */
+void guac_rdp_ai_process_formats(guac_client* client,
+        IWTSVirtualChannel* channel, wStream* stream);
+
+/**
+ * Processes a Open PDU received from the RDP server. The Open PDU is sent by
+ * the server to inform the client that the AUDIO_INPUT channel is now open.
+ *
+ * @param client
+ *     The guac_client associated with the current RDP connection.
+ *
+ * @param channel
+ *     The IWTSVirtualChannel instance associated with the connected
+ *     AUDIO_INPUT channel.
+ *
+ * @param stream
+ *     The received PDU, with the read position just after the message ID field
+ *     common to all AUDIO_INPUT PDUs.
+ */
+void guac_rdp_ai_process_open(guac_client* client,
+        IWTSVirtualChannel* channel, wStream* stream);
+
+/**
+ * Processes a Format Change PDU received from the RDP server. The Format
+ * Change PDU is sent by the server to request a different sound format.
+ *
+ * @param client
+ *     The guac_client associated with the current RDP connection.
+ *
+ * @param channel
+ *     The IWTSVirtualChannel instance associated with the connected
+ *     AUDIO_INPUT channel.
+ *
+ * @param stream
+ *     The received PDU, with the read position just after the message ID field
+ *     common to all AUDIO_INPUT PDUs.
+ */
+void guac_rdp_ai_process_formatchange(guac_client* client,
+        IWTSVirtualChannel* channel, wStream* stream);
+
+#endif
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/503ffb0d/src/protocols/rdp/guac_ai/ai_service.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/guac_ai/ai_service.c b/src/protocols/rdp/guac_ai/ai_service.c
index e822f90..d6538bc 100644
--- a/src/protocols/rdp/guac_ai/ai_service.c
+++ b/src/protocols/rdp/guac_ai/ai_service.c
@@ -19,6 +19,7 @@
 
 #include "config.h"
 
+#include "ai_messages.h"
 #include "ai_service.h"
 #include "ptr_string.h"
 #include "rdp.h"
@@ -47,18 +48,49 @@
  *     The guac_client associated with RDP connection having the AUDIO_INPUT
  *     connection along which the given data was received.
  *
+ * @param channel
+ *     A reference to the IWTSVirtualChannel instance along which responses
+ *     should be sent.
+ *
  * @param stream
  *     The data received along the AUDIO_INPUT channel.
  */
-static void guac_rdp_ai_handle_data(guac_client* client, wStream* stream) {
+static void guac_rdp_ai_handle_data(guac_client* client,
+        IWTSVirtualChannel* channel, wStream* stream) {
 
     /* Read message ID from received PDU */
     BYTE message_id;
     Stream_Read_UINT8(stream, message_id);
 
-    /* STUB */
-    guac_client_log(client, GUAC_LOG_DEBUG, "AUDIO_INPUT data received: 0x%x",
-            message_id);
+    /* Invoke appropriate message processor based on ID */
+    switch (message_id) {
+
+        /* Version PDU */
+        case GUAC_RDP_MSG_SNDIN_VERSION:
+            guac_rdp_ai_process_version(client, channel, stream);
+            break;
+
+        /* Sound Formats PDU */
+        case GUAC_RDP_MSG_SNDIN_FORMATS:
+            guac_rdp_ai_process_formats(client, channel, stream);
+            break;
+
+        /* Open PDU */
+        case GUAC_RDP_MSG_SNDIN_OPEN:
+            guac_rdp_ai_process_open(client, channel, stream);
+            break;
+
+        /* Format Change PDU */
+        case GUAC_RDP_MSG_SNDIN_FORMATCHANGE:
+            guac_rdp_ai_process_formatchange(client, channel, stream);
+            break;
+
+        /* Log unknown message IDs */
+        default:
+            guac_client_log(client, GUAC_LOG_DEBUG,
+                    "Unknown AUDIO_INPUT message ID: 0x%x", message_id);
+
+    }
 
 }
 
@@ -85,10 +117,11 @@ static int guac_rdp_ai_data(IWTSVirtualChannelCallback* channel_callback,
 
     guac_rdp_ai_channel_callback* ai_channel_callback =
         (guac_rdp_ai_channel_callback*) channel_callback;
+    IWTSVirtualChannel* channel = ai_channel_callback->channel;
 
     /* Invoke generalized (API-independent) data handler */
     wStream* stream = Stream_New(buffer, size);
-    guac_rdp_ai_handle_data(ai_channel_callback->client, stream);
+    guac_rdp_ai_handle_data(ai_channel_callback->client, channel, stream);
     Stream_Free(stream, FALSE);
 
     return 0;
@@ -114,9 +147,10 @@ static int guac_rdp_ai_data(IWTSVirtualChannelCallback* channel_callback,
 
     guac_rdp_ai_channel_callback* ai_channel_callback =
         (guac_rdp_ai_channel_callback*) channel_callback;
+    IWTSVirtualChannel* channel = ai_channel_callback->channel;
 
     /* Invoke generalized (API-independent) data handler */
-    guac_rdp_ai_handle_data(ai_channel_callback->client, stream);
+    guac_rdp_ai_handle_data(ai_channel_callback->client, channel, stream);
 
     return 0;
 
@@ -197,6 +231,7 @@ static int guac_rdp_ai_new_connection(
 
     /* Init listener callback with data from plugin */
     ai_channel_callback->client = ai_listener_callback->client;
+    ai_channel_callback->channel = channel;
     ai_channel_callback->parent.OnDataReceived = guac_rdp_ai_data;
     ai_channel_callback->parent.OnClose = guac_rdp_ai_close;
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/503ffb0d/src/protocols/rdp/guac_ai/ai_service.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/guac_ai/ai_service.h b/src/protocols/rdp/guac_ai/ai_service.h
index 4377812..28f2227 100644
--- a/src/protocols/rdp/guac_ai/ai_service.h
+++ b/src/protocols/rdp/guac_ai/ai_service.h
@@ -64,6 +64,12 @@ typedef struct guac_rdp_ai_channel_callback {
     IWTSVirtualChannelCallback parent;
 
     /**
+     * The actual virtual channel instance along which the AUDIO_INPUT plugin
+     * should send any responses.
+     */
+    IWTSVirtualChannel* channel;
+
+    /**
      * The guac_client instance associated with the RDP connection using the
      * AUDIO_INPUT plugin.
      */


[13/26] incubator-guacamole-server git commit: GUACAMOLE-25: Add stub callbacks for AUDIO_INPUT data handling.

Posted by jm...@apache.org.
GUACAMOLE-25: Add stub callbacks for AUDIO_INPUT data handling.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/ac94fd4c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/ac94fd4c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/ac94fd4c

Branch: refs/heads/master
Commit: ac94fd4cd02f819cceb66206d6216e12c3ab93e2
Parents: 9cd89e6
Author: Michael Jumper <mj...@apache.org>
Authored: Sat Apr 16 22:48:27 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 13:50:28 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/guac_ai/ai_service.c | 224 +++++++++++++++++++++++++++-
 src/protocols/rdp/guac_ai/ai_service.h |  77 +++++++++-
 2 files changed, 296 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/ac94fd4c/src/protocols/rdp/guac_ai/ai_service.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/guac_ai/ai_service.c b/src/protocols/rdp/guac_ai/ai_service.c
index c6ff47b..5b72354 100644
--- a/src/protocols/rdp/guac_ai/ai_service.c
+++ b/src/protocols/rdp/guac_ai/ai_service.c
@@ -38,6 +38,208 @@
 #endif
 
 /**
+ * Handles the given data received along the AUDIO_INPUT channel of the RDP
+ * connection associated with the given guac_client. This handler is
+ * API-independent and is invoked by API-dependent guac_rdp_ai_data callback
+ * specific to the version of FreeRDP installed.
+ *
+ * @param client
+ *     The guac_client associated with RDP connection having the AUDIO_INPUT
+ *     connection along which the given data was received.
+ *
+ * @param stream
+ *     The data received along the AUDIO_INPUT channel.
+ */
+static void guac_rdp_ai_handle_data(guac_client* client, wStream* stream) {
+
+    /* Read message ID from received PDU */
+    BYTE message_id;
+    Stream_Read_UINT8(stream, message_id);
+
+    /* STUB */
+    guac_client_log(client, GUAC_LOG_DEBUG, "AUDIO_INPUT data received: 0x%x",
+            message_id);
+
+}
+
+/**
+ * Callback which is invoked when data is received along a connection to the
+ * AUDIO_INPUT plugin. This callback is specific to FreeRDP 1.1 and older.
+ *
+ * @param channel_callback
+ *     The IWTSVirtualChannelCallback structure to which this callback was
+ *     originally assigned.
+ *
+ * @param size
+ *     The number of bytes received.
+ *
+ * @param buffer
+ *     A buffer containing all bytes received.
+ *
+ * @return
+ *     Always zero.
+ */
+static int guac_rdp_ai_data(IWTSVirtualChannelCallback* channel_callback,
+        UINT32 size, BYTE* buffer) {
+
+    guac_rdp_ai_channel_callback* ai_channel_callback =
+        (guac_rdp_ai_channel_callback*) channel_callback;
+
+    /* Invoke generalized (API-independent) data handler */
+    wStream* stream = Stream_New(buffer, size);
+    guac_rdp_ai_handle_data(ai_channel_callback->client, stream);
+    Stream_Free(stream, FALSE);
+
+    return 0;
+
+}
+
+/**
+ * Callback which is invoked when a connection to the AUDIO_INPUT plugin is
+ * closed.
+ *
+ * @param channel_callback
+ *     The IWTSVirtualChannelCallback structure to which this callback was
+ *     originally assigned.
+ *
+ * @return
+ *     Always zero.
+ */
+static int guac_rdp_ai_close(IWTSVirtualChannelCallback* channel_callback) {
+
+    guac_rdp_ai_channel_callback* ai_channel_callback =
+        (guac_rdp_ai_channel_callback*) channel_callback;
+
+    /* Log closure of AUDIO_INPUT channel */
+    guac_client_log(ai_channel_callback->client, GUAC_LOG_DEBUG,
+            "AUDIO_INPUT channel connection closed");
+
+    free(ai_channel_callback);
+    return 0;
+
+}
+
+/**
+ * Callback which is invoked when a new connection is received by the
+ * AUDIO_INPUT plugin. Additional callbacks required to handle received data
+ * and closure of the connection must be installed at this point.
+ *
+ * @param listener_callback
+ *     The IWTSListenerCallback structure associated with the AUDIO_INPUT
+ *     plugin receiving the new connection.
+ *
+ * @param channel
+ *     A reference to the IWTSVirtualChannel instance along which data related
+ *     to the AUDIO_INPUT channel should be sent.
+ *
+ * @param data
+ *     Absolutely no idea. According to Microsoft's documentation for the
+ *     function prototype on which FreeRDP's API appears to be based: "This
+ *     parameter is not implemented and is reserved for future use."
+ *
+ * @param accept
+ *     Pointer to a flag which should be set to TRUE if the connection should
+ *     be accepted or FALSE otherwise. In the case of FreeRDP, this value
+ *     defaults to TRUE, and TRUE absolutely MUST be identically 1 or it will
+ *     be interpreted as FALSE.
+ *
+ * @param channel_callback
+ *     A pointer to the location that the new IWTSVirtualChannelCallback
+ *     structure containing the required callbacks should be assigned.
+ *
+ * @return
+ *     Always zero.
+ */
+static int guac_rdp_ai_new_connection(
+        IWTSListenerCallback* listener_callback, IWTSVirtualChannel* channel,
+        BYTE* data, int* accept,
+        IWTSVirtualChannelCallback** channel_callback) {
+
+    guac_rdp_ai_listener_callback* ai_listener_callback =
+        (guac_rdp_ai_listener_callback*) listener_callback;
+
+    /* Log new AUDIO_INPUT connection */
+    guac_client_log(ai_listener_callback->client, GUAC_LOG_DEBUG,
+            "New AUDIO_INPUT channel connection");
+
+    /* Allocate new channel callback */
+    guac_rdp_ai_channel_callback* ai_channel_callback =
+        calloc(1, sizeof(guac_rdp_ai_channel_callback));
+
+    /* Init listener callback with data from plugin */
+    ai_channel_callback->client = ai_listener_callback->client;
+    ai_channel_callback->parent.OnDataReceived = guac_rdp_ai_data;
+    ai_channel_callback->parent.OnClose = guac_rdp_ai_close;
+
+    /* Return callback through pointer */
+    *channel_callback = (IWTSVirtualChannelCallback*) ai_channel_callback;
+    return 0;
+
+}
+
+/**
+ * Callback which is invoked when the AUDIO_INPUT plugin has been loaded and
+ * needs to be initialized with other callbacks and data.
+ *
+ * @param plugin
+ *     The AUDIO_INPUT plugin that needs to be initialied.
+ *
+ * @param manager
+ *     The IWTSVirtualChannelManager instance with which the AUDIO_INPUT plugin
+ *     must be registered.
+ *
+ * @return
+ *     Always zero.
+ */
+static int guac_rdp_ai_initialize(IWTSPlugin* plugin,
+        IWTSVirtualChannelManager* manager) {
+
+    /* Allocate new listener callback */
+    guac_rdp_ai_listener_callback* ai_listener_callback =
+        calloc(1, sizeof(guac_rdp_ai_listener_callback));
+
+    /* Ensure listener callback is freed when plugin is terminated */
+    guac_rdp_ai_plugin* ai_plugin = (guac_rdp_ai_plugin*) plugin;
+    ai_plugin->listener_callback = ai_listener_callback;
+
+    /* Init listener callback with data from plugin */
+    ai_listener_callback->client = ai_plugin->client;
+    ai_listener_callback->parent.OnNewChannelConnection =
+        guac_rdp_ai_new_connection;
+
+    /* Register listener for "AUDIO_INPUT" channel */
+    manager->CreateListener(manager, "AUDIO_INPUT", 0,
+            (IWTSListenerCallback*) ai_listener_callback, NULL);
+
+    return 0;
+
+}
+
+/**
+ * Callback which is invoked when all connections to the AUDIO_INPUT plugin
+ * have closed and the plugin is being unloaded.
+ *
+ * @param plugin
+ *     The AUDIO_INPUT plugin being unloaded.
+ *
+ * @return
+ *     Always zero.
+ */
+static int guac_rdp_ai_terminated(IWTSPlugin* plugin) {
+
+    guac_rdp_ai_plugin* ai_plugin = (guac_rdp_ai_plugin*) plugin;
+    guac_client* client = ai_plugin->client;
+
+    /* Free all non-FreeRDP data */
+    free(ai_plugin->listener_callback);
+    free(ai_plugin);
+
+    guac_client_log(client, GUAC_LOG_DEBUG, "AUDIO_INPUT plugin unloaded.");
+    return 0;
+
+}
+
+/**
  * Entry point for AUDIO_INPUT dynamic virtual channel.
  */
 int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) {
@@ -45,9 +247,25 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) {
     ADDIN_ARGV* args = pEntryPoints->GetPluginData(pEntryPoints);
     guac_client* client = (guac_client*) guac_rdp_string_to_ptr(args->argv[1]);
 
-    /* STUB */
-    guac_client_log(client, GUAC_LOG_DEBUG,
-            "STUB: AUDIO_INPUT DVC (entry point)");
+    /* Pull previously-allocated plugin */
+    guac_rdp_ai_plugin* ai_plugin = (guac_rdp_ai_plugin*)
+        pEntryPoints->GetPlugin(pEntryPoints, "guacai");
+
+    /* If no such plugin allocated, allocate and register it now */
+    if (ai_plugin == NULL) {
+
+        /* Init plugin callbacks and data */
+        ai_plugin = calloc(1, sizeof(guac_rdp_ai_plugin));
+        ai_plugin->parent.Initialize = guac_rdp_ai_initialize;
+        ai_plugin->parent.Terminated = guac_rdp_ai_terminated;
+        ai_plugin->client = client;
+
+        /* Register plugin as "guacai" for later retrieval */
+        pEntryPoints->RegisterPlugin(pEntryPoints, "guacai",
+                (IWTSPlugin*) ai_plugin);
+
+        guac_client_log(client, GUAC_LOG_DEBUG, "AUDIO_INPUT plugin loaded.");
+    }
 
     return 1;
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/ac94fd4c/src/protocols/rdp/guac_ai/ai_service.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/guac_ai/ai_service.h b/src/protocols/rdp/guac_ai/ai_service.h
index caa62ad..4377812 100644
--- a/src/protocols/rdp/guac_ai/ai_service.h
+++ b/src/protocols/rdp/guac_ai/ai_service.h
@@ -17,13 +17,86 @@
  * under the License.
  */
 
-
 #ifndef GUAC_RDP_AI_SERVICE_H
 #define GUAC_RDP_AI_SERVICE_H
 
 #include "config.h"
 
-/* STUB */
+#include <freerdp/freerdp.h>
+#include <freerdp/constants.h>
+#include <freerdp/dvc.h>
+#include <guacamole/client.h>
+
+/**
+ * Extended version of the IWTSListenerCallback structure, providing additional
+ * access to Guacamole-specific data. The IWTSListenerCallback provides access
+ * to callbacks related to the receipt of new connections to the AUDIO_INPUT
+ * channel.
+ */
+typedef struct guac_rdp_ai_listener_callback {
+
+    /**
+     * The parent IWTSListenerCallback structure that this structure extends.
+     * THIS MEMBER MUST BE FIRST!
+     */
+    IWTSListenerCallback parent;
+
+    /**
+     * The guac_client instance associated with the RDP connection using the
+     * AUDIO_INPUT plugin.
+     */
+    guac_client* client;
+
+} guac_rdp_ai_listener_callback;
+
+/**
+ * Extended version of the IWTSVirtualChannelCallback structure, providing
+ * additional access to Guacamole-specific data. The IWTSVirtualChannelCallback
+ * provides access to callbacks related to an active connection to the
+ * AUDIO_INPUT channel, including receipt of data. 
+ */
+typedef struct guac_rdp_ai_channel_callback {
+
+    /**
+     * The parent IWTSVirtualChannelCallback structure that this structure
+     * extends. THIS MEMBER MUST BE FIRST!
+     */
+    IWTSVirtualChannelCallback parent;
+
+    /**
+     * The guac_client instance associated with the RDP connection using the
+     * AUDIO_INPUT plugin.
+     */
+    guac_client* client;
+
+} guac_rdp_ai_channel_callback;
+
+/**
+ * All data associated with Guacamole's AUDIO_INPUT plugin for FreeRDP.
+ */
+typedef struct guac_rdp_ai_plugin {
+
+    /**
+     * The parent IWTSPlugin structure that this structure extends. THIS
+     * MEMBER MUST BE FIRST!
+     */
+    IWTSPlugin parent;
+
+    /**
+     * The listener callback structure allocated when the AUDIO_INPUT plugin
+     * was loaded, if any. If the plugin did not fully load, this will be NULL.
+     * If non-NULL, this callback structure must be freed when the plugin is
+     * terminated.
+     */
+    guac_rdp_ai_listener_callback* listener_callback;
+
+    /**
+     * The guac_client instance associated with the RDP connection using the
+     * AUDIO_INPUT plugin.
+     */
+    guac_client* client;
+
+} guac_rdp_ai_plugin;
 
 #endif
 


[24/26] incubator-guacamole-server git commit: GUACAMOLE-25: Reset I/O counters upon end-of-stream.

Posted by jm...@apache.org.
GUACAMOLE-25: Reset I/O counters upon end-of-stream.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/0d29694a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/0d29694a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/0d29694a

Branch: refs/heads/master
Commit: 0d29694afc2c7eb1fa8a8fea011bd5a7ec9a99ac
Parents: 0be04ea
Author: Michael Jumper <mj...@apache.org>
Authored: Wed Jun 1 16:20:38 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Jun 1 16:20:38 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/audio_input.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/0d29694a/src/protocols/rdp/audio_input.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.c b/src/protocols/rdp/audio_input.c
index eefb231..dc078dc 100644
--- a/src/protocols/rdp/audio_input.c
+++ b/src/protocols/rdp/audio_input.c
@@ -247,9 +247,6 @@ void guac_rdp_audio_buffer_set_stream(guac_rdp_audio_buffer* audio_buffer,
     audio_buffer->in_format.channels = channels;
     audio_buffer->in_format.bps = bps;
 
-    /* Reset input counter */
-    audio_buffer->total_bytes_received = 0;
-
     /* Acknowledge stream creation (if buffer is ready to receive) */
     guac_rdp_audio_buffer_ack(audio_buffer,
             "OK", GUAC_PROTOCOL_STATUS_SUCCESS);
@@ -274,9 +271,6 @@ void guac_rdp_audio_buffer_set_output(guac_rdp_audio_buffer* audio_buffer,
     audio_buffer->out_format.channels = channels;
     audio_buffer->out_format.bps = bps;
 
-    /* Reset output counter */
-    audio_buffer->total_bytes_sent = 0;
-
     pthread_mutex_unlock(&(audio_buffer->lock));
 
 }
@@ -470,6 +464,10 @@ void guac_rdp_audio_buffer_end(guac_rdp_audio_buffer* audio_buffer) {
     audio_buffer->packet_size = 0;
     audio_buffer->flush_handler = NULL;
 
+    /* Reset I/O counters */
+    audio_buffer->total_bytes_sent = 0;
+    audio_buffer->total_bytes_received = 0;
+
     /* Free packet (if any) */
     free(audio_buffer->packet);
     audio_buffer->packet = NULL;


[15/26] incubator-guacamole-server git commit: GUACAMOLE-25: Buffer and send Data PDUs as necessary.

Posted by jm...@apache.org.
GUACAMOLE-25: Buffer and send Data PDUs as necessary.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/9d5871a3
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/9d5871a3
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/9d5871a3

Branch: refs/heads/master
Commit: 9d5871a3c8a9af7522beed65d80f7630cc90f7a7
Parents: 63cd2ce
Author: Michael Jumper <mj...@apache.org>
Authored: Mon Apr 18 00:32:51 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 13:50:28 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/Makefile.am           |   1 +
 src/protocols/rdp/audio_input.c         |  90 ++++++++++++++++++-
 src/protocols/rdp/audio_input.h         | 126 +++++++++++++++++++++++++++
 src/protocols/rdp/client.c              |   5 ++
 src/protocols/rdp/guac_ai/ai_messages.c |  35 +++++++-
 src/protocols/rdp/guac_ai/ai_service.c  |   8 +-
 src/protocols/rdp/rdp.c                 |   4 +-
 src/protocols/rdp/rdp.h                 |   6 ++
 8 files changed, 270 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/9d5871a3/src/protocols/rdp/Makefile.am
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/Makefile.am b/src/protocols/rdp/Makefile.am
index 0d07a74..f76c33e 100644
--- a/src/protocols/rdp/Makefile.am
+++ b/src/protocols/rdp/Makefile.am
@@ -47,6 +47,7 @@ libguac_client_rdp_la_SOURCES = \
     user.c
 
 guacai_sources =          \
+    audio_input.c         \
     guac_ai/ai_messages.c \
     guac_ai/ai_service.c  \
     ptr_string.c

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/9d5871a3/src/protocols/rdp/audio_input.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.c b/src/protocols/rdp/audio_input.c
index 9d5d505..1bea175 100644
--- a/src/protocols/rdp/audio_input.c
+++ b/src/protocols/rdp/audio_input.c
@@ -51,14 +51,19 @@ int guac_rdp_audio_handler(guac_user* user, guac_stream* stream,
 int guac_rdp_audio_blob_handler(guac_user* user, guac_stream* stream,
         void* data, int length) {
 
-    /* STUB */
+    guac_client* client = user->client;
+    guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
+
+    /* Write blob to audio stream, buffering if necessary */
+    guac_rdp_audio_buffer_write(rdp_client->audio_input, data, length);
+
     return 0;
 
 }
 
 int guac_rdp_audio_end_handler(guac_user* user, guac_stream* stream) {
 
-    /* STUB */
+    /* Ignore - the AUDIO_INPUT channel will simply not receive anything */
     return 0;
 
 }
@@ -77,3 +82,84 @@ void guac_rdp_audio_load_plugin(rdpContext* context) {
 
 }
 
+guac_rdp_audio_buffer* guac_rdp_audio_buffer_alloc() {
+    return calloc(1, sizeof(guac_rdp_audio_buffer));
+}
+
+void guac_rdp_audio_buffer_begin(guac_rdp_audio_buffer* audio_buffer,
+        int packet_size, guac_rdp_audio_buffer_flush_handler* flush_handler,
+        void* data) {
+
+    /* Reset buffer state to provided values */
+    audio_buffer->bytes_written = 0;
+    audio_buffer->packet_size = packet_size;
+    audio_buffer->flush_handler = flush_handler;
+    audio_buffer->data = data;
+
+    /* Allocate new buffer */
+    free(audio_buffer->packet);
+    audio_buffer->packet = malloc(packet_size);
+
+}
+
+void guac_rdp_audio_buffer_write(guac_rdp_audio_buffer* audio_buffer,
+        char* buffer, int length) {
+
+    /* Ignore packet if there is no buffer */
+    if (audio_buffer->packet_size == 0 || audio_buffer->packet == NULL)
+        return;
+
+    /* Continuously write packets until no data remains */
+    while (length > 0) {
+
+        /* Calculate ideal size of chunk based on available space */
+        int chunk_size = audio_buffer->packet_size
+                       - audio_buffer->bytes_written;
+
+        /* Shrink chunk size if insufficient bytes are provided */
+        if (length < chunk_size)
+            chunk_size = length;
+
+        /* Append buffer */
+        memcpy(audio_buffer->packet + audio_buffer->bytes_written,
+                buffer, chunk_size);
+
+        /* Update byte counters */
+        length -= chunk_size;
+        audio_buffer->bytes_written += chunk_size;
+
+        /* Invoke flush handler if full */
+        if (audio_buffer->bytes_written == audio_buffer->packet_size) {
+
+            /* Only actually invoke if defined */
+            if (audio_buffer->flush_handler)
+                audio_buffer->flush_handler(audio_buffer->packet,
+                        audio_buffer->bytes_written, audio_buffer->data);
+
+            /* Reset buffer in all cases */
+            audio_buffer->bytes_written = 0;
+
+        }
+
+    } /* end packet write loop */
+
+}
+
+void guac_rdp_audio_buffer_end(guac_rdp_audio_buffer* audio_buffer) {
+
+    /* Reset buffer state */
+    audio_buffer->bytes_written = 0;
+    audio_buffer->packet_size = 0;
+    audio_buffer->flush_handler = NULL;
+
+    /* Free packet (if any) */
+    free(audio_buffer->packet);
+    audio_buffer->packet = NULL;
+
+}
+
+void guac_rdp_audio_buffer_free(guac_rdp_audio_buffer* audio_buffer) {
+    free(audio_buffer->packet);
+    free(audio_buffer);
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/9d5871a3/src/protocols/rdp/audio_input.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.h b/src/protocols/rdp/audio_input.h
index d32cda1..c89de15 100644
--- a/src/protocols/rdp/audio_input.h
+++ b/src/protocols/rdp/audio_input.h
@@ -26,6 +26,132 @@
 #include <guacamole/user.h>
 
 /**
+ * Handler which is invoked when a guac_rdp_audio_buffer's internal packet
+ * buffer has reached capacity and must be flushed.
+ *
+ * @param buffer
+ *     The buffer which needs to be flushed as an audio packet.
+ *
+ * @param length
+ *     The number of bytes stored within the buffer. This is guaranteed to be
+ *     identical to the packet_size value specified when the audio buffer was
+ *     initialized.
+ *
+ * @param data
+ *     The arbitrary data pointer provided when the audio buffer was
+ *     initialized.
+ */
+typedef void guac_rdp_audio_buffer_flush_handler(char* buffer, int length,
+        void* data);
+
+/**
+ * A buffer of arbitrary audio data. Received audio data can be written to this
+ * buffer, and will automatically be flushed via a given handler once the
+ * internal buffer reaches capacity.
+ */
+typedef struct guac_rdp_audio_buffer {
+
+    /**
+     * The size that each audio packet must be, in bytes. The packet buffer
+     * within this structure will be at least this size.
+     */
+    int packet_size;
+
+    /**
+     * The number of bytes currently stored within the packet buffer.
+     */
+    int bytes_written;
+
+    /**
+     * All audio data being prepared for sending to the AUDIO_INPUT channel.
+     */
+    char* packet;
+
+    /**
+     * Handler function which will be invoked when a full audio packet is
+     * ready to be flushed to the AUDIO_INPUT channel, if defined. If NULL,
+     * audio packets will simply be ignored.
+     */
+    guac_rdp_audio_buffer_flush_handler* flush_handler;
+
+    /**
+     * Arbitrary data assigned by the AUDIO_INPUT plugin implementation.
+     */
+    void* data;
+
+} guac_rdp_audio_buffer;
+
+/**
+ * Allocates a new audio buffer. The new audio buffer will ignore any received
+ * data until guac_rdp_audio_buffer_begin() is invoked, and will resume
+ * ignoring received data once guac_rdp_audio_buffer_end() is invoked.
+ *
+ * @return
+ *     A newly-allocated audio buffer.
+ */
+guac_rdp_audio_buffer* guac_rdp_audio_buffer_alloc();
+
+/**
+ * Begins handling of audio data received via guac_rdp_audio_buffer_write() and
+ * allocates the necessary underlying packet buffer. Audio packets of exactly
+ * packet_size bytes will be flushed as available using the provided
+ * flush_handler.
+ *
+ * @param audio_buffer
+ *     The audio buffer to begin.
+ *
+ * @param packet_size
+ *     The number of bytes to include in all audio packets provided to the
+ *     given flush_handler.
+ *
+ * @param flush_handler
+ *     The function to invoke when an audio packet must be flushed.
+ *
+ * @param data
+ *     Arbitrary data to provide to the flush_handler when an audio packet
+ *     needs to be flushed.
+ */
+void guac_rdp_audio_buffer_begin(guac_rdp_audio_buffer* audio_buffer,
+        int packet_size, guac_rdp_audio_buffer_flush_handler* flush_handler,
+        void* data);
+
+/**
+ * Writes the given buffer of audio data to the given audio buffer. A new
+ * packet will be flushed using the associated flush handler once sufficient
+ * bytes have been accumulated.
+ *
+ * @param audio_buffer
+ *     The audio buffer to which the given audio data should be written.
+ *
+ * @param buffer
+ *     The buffer of audio data to write to the given audio buffer.
+ *
+ * @param length
+ *     The number of bytes to write.
+ */
+void guac_rdp_audio_buffer_write(guac_rdp_audio_buffer* audio_buffer,
+        char* buffer, int length);
+
+/**
+ * Stops handling of audio data received via guac_rdp_audio_buffer_write() and
+ * frees the underlying packet buffer. Further audio data will be ignored until
+ * guac_rdp_audio_buffer_begin() is invoked again.
+ *
+ * @param audio_buffer
+ *     The audio buffer to end.
+ */
+void guac_rdp_audio_buffer_end(guac_rdp_audio_buffer* audio_buffer);
+
+/**
+ * Frees the given audio buffer. If guac_rdp_audio_buffer_end() has not yet
+ * been called, its associated packet buffer will also be freed.
+ *
+ * @param audio_buffer
+ *     The audio buffer to free.
+ */
+void guac_rdp_audio_buffer_free(guac_rdp_audio_buffer* audio_buffer);
+
+/**
  * Handler for inbound audio data (audio input).
  */
 guac_user_audio_handler guac_rdp_audio_handler;

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/9d5871a3/src/protocols/rdp/client.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/client.c b/src/protocols/rdp/client.c
index 5132125..362f0aa 100644
--- a/src/protocols/rdp/client.c
+++ b/src/protocols/rdp/client.c
@@ -19,6 +19,7 @@
 
 #include "config.h"
 
+#include "audio_input.h"
 #include "client.h"
 #include "rdp.h"
 #include "rdp_disp.h"
@@ -129,6 +130,10 @@ int guac_rdp_client_free_handler(guac_client* client) {
     if (rdp_client->audio != NULL)
         guac_audio_stream_free(rdp_client->audio);
 
+    /* Clean up audio input buffer, if allocated */
+    if (rdp_client->audio_input != NULL)
+        guac_rdp_audio_buffer_free(rdp_client->audio_input);
+
     /* Free client data */
     guac_common_clipboard_free(rdp_client->clipboard);
     free(rdp_client);

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/9d5871a3/src/protocols/rdp/guac_ai/ai_messages.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/guac_ai/ai_messages.c b/src/protocols/rdp/guac_ai/ai_messages.c
index 8b2d0d7..b0eb6cf 100644
--- a/src/protocols/rdp/guac_ai/ai_messages.c
+++ b/src/protocols/rdp/guac_ai/ai_messages.c
@@ -20,6 +20,7 @@
 #include "config.h"
 
 #include "ai_messages.h"
+#include "audio_input.h"
 #include "rdp.h"
 
 #include <stdlib.h>
@@ -112,6 +113,21 @@ static void guac_rdp_ai_send_incoming_data(IWTSVirtualChannel* channel) {
 
 }
 
+static void guac_rdp_ai_send_data(IWTSVirtualChannel* channel,
+        char* buffer, int length) {
+
+    /* Build data PDU */
+    wStream* stream = Stream_New(NULL, length + 1);
+    Stream_Write_UINT8(stream, GUAC_RDP_MSG_SNDIN_DATA); /* MessageId */
+    Stream_Write(stream, buffer, length); /* Data */
+
+    /* Send stream */
+    channel->Write(channel, (UINT32) Stream_GetPosition(stream),
+            Stream_Buffer(stream), NULL);
+    Stream_Free(stream, TRUE);
+
+}
+
 /**
  * Sends a Sound Formats PDU along the given channel. A Sound Formats PDU is
  * used by the client to indicate to the server which formats of audio it
@@ -263,9 +279,22 @@ void guac_rdp_ai_process_formats(guac_client* client,
 
 }
 
+static void guac_rdp_ai_flush_packet(char* buffer, int length, void* data) {
+
+    IWTSVirtualChannel* channel = (IWTSVirtualChannel*) data;
+
+    /* Send data over channel */
+    guac_rdp_ai_send_incoming_data(channel);
+    guac_rdp_ai_send_data(channel, buffer, length);
+
+}
+
 void guac_rdp_ai_process_open(guac_client* client,
         IWTSVirtualChannel* channel, wStream* stream) {
 
+    guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
+    guac_rdp_audio_buffer* audio_buffer = rdp_client->audio_input;
+
     UINT32 packet_frames;
     UINT32 initial_format;
 
@@ -281,12 +310,16 @@ void guac_rdp_ai_process_open(guac_client* client,
     guac_rdp_ai_send_formatchange(channel, initial_format);
     guac_rdp_ai_send_open_reply(channel, 0);
 
+    /* FIXME: Assuming mimetype of 16-bit 44100 Hz stereo PCM */
+    guac_rdp_audio_buffer_begin(audio_buffer, packet_frames * 2 * 2,
+            guac_rdp_ai_flush_packet, channel);
+
 }
 
 void guac_rdp_ai_process_formatchange(guac_client* client,
         IWTSVirtualChannel* channel, wStream* stream) {
 
-    /* STUB */
+    /* STUB: Should not be called as we only accept one format */
     guac_client_log(client, GUAC_LOG_DEBUG, "AUDIO_INPUT: formatchange");
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/9d5871a3/src/protocols/rdp/guac_ai/ai_service.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/guac_ai/ai_service.c b/src/protocols/rdp/guac_ai/ai_service.c
index d6538bc..945f039 100644
--- a/src/protocols/rdp/guac_ai/ai_service.c
+++ b/src/protocols/rdp/guac_ai/ai_service.c
@@ -21,6 +21,7 @@
 
 #include "ai_messages.h"
 #include "ai_service.h"
+#include "audio_input.h"
 #include "ptr_string.h"
 #include "rdp.h"
 
@@ -173,10 +174,15 @@ static int guac_rdp_ai_close(IWTSVirtualChannelCallback* channel_callback) {
     guac_rdp_ai_channel_callback* ai_channel_callback =
         (guac_rdp_ai_channel_callback*) channel_callback;
 
+    guac_client* client = ai_channel_callback->client;
+    guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
+    guac_rdp_audio_buffer* audio_buffer = rdp_client->audio_input;
+
     /* Log closure of AUDIO_INPUT channel */
-    guac_client_log(ai_channel_callback->client, GUAC_LOG_DEBUG,
+    guac_client_log(client, GUAC_LOG_DEBUG,
             "AUDIO_INPUT channel connection closed");
 
+    guac_rdp_audio_buffer_end(audio_buffer);
     free(ai_channel_callback);
     return 0;
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/9d5871a3/src/protocols/rdp/rdp.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c
index 7859e20..f461369 100644
--- a/src/protocols/rdp/rdp.c
+++ b/src/protocols/rdp/rdp.c
@@ -244,8 +244,10 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
 #endif
 
             /* Load "AUDIO_INPUT" plugin for audio input*/
-            if (settings->enable_audio_input)
+            if (settings->enable_audio_input) {
+                rdp_client->audio_input = guac_rdp_audio_buffer_alloc();
                 guac_rdp_audio_load_plugin(instance->context);
+            }
 
         }
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/9d5871a3/src/protocols/rdp/rdp.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/rdp.h b/src/protocols/rdp/rdp.h
index 9325a18..02d9ac6 100644
--- a/src/protocols/rdp/rdp.h
+++ b/src/protocols/rdp/rdp.h
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include "audio_input.h"
 #include "guac_clipboard.h"
 #include "guac_display.h"
 #include "guac_surface.h"
@@ -121,6 +122,11 @@ typedef struct guac_rdp_client {
     guac_audio_stream* audio;
 
     /**
+     * Audio input buffer, if audio input is enabled.
+     */
+    guac_rdp_audio_buffer* audio_input;
+
+    /**
      * The filesystem being shared, if any.
      */
     guac_rdp_fs* filesystem;


[07/26] incubator-guacamole-server git commit: GUACAMOLE-25: Add stub "guacai" plugin for AUDIO_INPUT channel support.

Posted by jm...@apache.org.
GUACAMOLE-25: Add stub "guacai" plugin for AUDIO_INPUT channel support.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/21ab9d76
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/21ab9d76
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/21ab9d76

Branch: refs/heads/master
Commit: 21ab9d765da8c0b519d6aa7c90813adf4fb9705e
Parents: ec93a29
Author: Michael Jumper <mj...@apache.org>
Authored: Sat Apr 16 15:54:26 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 13:50:28 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/Makefile.am          | 38 +++++++++++++++
 src/protocols/rdp/audio_input.c        | 74 +++++++++++++++++++++++++++++
 src/protocols/rdp/audio_input.h        | 54 +++++++++++++++++++++
 src/protocols/rdp/guac_ai/ai_service.c | 56 ++++++++++++++++++++++
 src/protocols/rdp/guac_ai/ai_service.h | 29 +++++++++++
 src/protocols/rdp/rdp.c                | 30 ++++++++----
 src/protocols/rdp/rdp_settings.c       | 12 +++++
 src/protocols/rdp/rdp_settings.h       |  5 ++
 src/protocols/rdp/user.c               |  5 ++
 9 files changed, 293 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/21ab9d76/src/protocols/rdp/Makefile.am
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/Makefile.am b/src/protocols/rdp/Makefile.am
index 91593cb..44f248a 100644
--- a/src/protocols/rdp/Makefile.am
+++ b/src/protocols/rdp/Makefile.am
@@ -24,6 +24,7 @@ lib_LTLIBRARIES = libguac-client-rdp.la
 
 libguac_client_rdp_la_SOURCES = \
     _generated_keymaps.c        \
+    audio_input.c               \
     client.c                    \
     input.c                     \
     rdp.c                       \
@@ -44,6 +45,9 @@ libguac_client_rdp_la_SOURCES = \
     unicode.c                   \
     user.c
 
+guacai_sources =         \
+    guac_ai/ai_service.c
+
 guacsvc_sources =          \
     guac_svc/svc_service.c \
     rdp_svc.c
@@ -68,6 +72,7 @@ guacdr_sources =                             \
 noinst_HEADERS =                             \
     compat/client-cliprdr.h                  \
     compat/rail.h                            \
+    guac_ai/ai_service.h                     \
     guac_rdpdr/rdpdr_fs_messages.h           \
     guac_rdpdr/rdpdr_fs_messages_dir_info.h  \
     guac_rdpdr/rdpdr_fs_messages_file_info.h \
@@ -79,6 +84,7 @@ noinst_HEADERS =                             \
     guac_rdpsnd/rdpsnd_messages.h            \
     guac_rdpsnd/rdpsnd_service.h             \
     guac_svc/svc_service.h                   \
+    audio_input.h                            \
     client.h                                 \
     input.h                                  \
     rdp.h                                    \
@@ -104,6 +110,7 @@ noinst_HEADERS =                             \
 if ! ENABLE_WINPR
 noinst_HEADERS  += compat/winpr-stream.h compat/winpr-wtypes.h
 libguac_client_rdp_la_SOURCES += compat/winpr-stream.c
+guacai_sources  += compat/winpr-stream.c
 guacsvc_sources += compat/winpr-stream.c
 guacsnd_sources += compat/winpr-stream.c
 guacdr_sources  += compat/winpr-stream.c
@@ -149,6 +156,25 @@ guacdr_libadd =     \
     @LIBGUAC_LTLIB@
 
 #
+# Audio Input
+#
+
+guacai_cflags               =  \
+    -Werror -Wall -Iinclude    \
+    @COMMON_INCLUDE@           \
+    @COMMON_SSH_INCLUDE@       \
+    @LIBGUAC_INCLUDE@
+
+guacai_ldflags =                   \
+    -module -avoid-version -shared \
+    @PTHREAD_LIBS@                 \
+    @RDP_LIBS@
+
+guacai_libadd =     \
+    @COMMON_LTLIB@  \
+    @LIBGUAC_LTLIB@
+
+#
 # RDPSND
 #
 
@@ -224,10 +250,16 @@ if LEGACY_FREERDP_EXTENSIONS
 
 # FreeRDP 1.0-style extensions
 freerdp_LTLIBRARIES = \
+    guacai.la         \
     guacdr.la         \
     guacsnd.la        \
     guacsvc.la
 
+guacai_la_SOURCES = ${guacai_sources}
+guacai_la_CFLAGS  = ${guacai_cflags}
+guacai_la_LDFLAGS = ${guacai_ldflags}
+guacai_la_LIBADD  = ${guacai_libadd}
+
 guacdr_la_SOURCES = ${guacdr_sources}
 guacdr_la_CFLAGS  = ${guacdr_cflags}
 guacdr_la_LDFLAGS = ${guacdr_ldflags}
@@ -247,10 +279,16 @@ else
 
 # FreeRDP 1.1 (and hopefully onward) extensions
 freerdp_LTLIBRARIES = \
+    guacai-client.la  \
     guacdr-client.la  \
     guacsnd-client.la \
     guacsvc-client.la
 
+guacai_client_la_SOURCES = ${guacai_sources}
+guacai_client_la_CFLAGS  = ${guacai_cflags}
+guacai_client_la_LDFLAGS = ${guacai_ldflags}
+guacai_client_la_LIBADD  = ${guacai_libadd}
+
 guacdr_client_la_SOURCES = ${guacdr_sources}
 guacdr_client_la_CFLAGS  = ${guacdr_cflags}
 guacdr_client_la_LDFLAGS = ${guacdr_ldflags}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/21ab9d76/src/protocols/rdp/audio_input.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.c b/src/protocols/rdp/audio_input.c
new file mode 100644
index 0000000..8233184
--- /dev/null
+++ b/src/protocols/rdp/audio_input.c
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "config.h"
+#include "audio_input.h"
+
+#include <freerdp/freerdp.h>
+#include <freerdp/channels/channels.h>
+#include <guacamole/protocol.h>
+#include <guacamole/socket.h>
+#include <guacamole/stream.h>
+#include <guacamole/user.h>
+
+#include <stdlib.h>
+
+int guac_rdp_audio_handler(guac_user* user, guac_stream* stream,
+        char* mimetype) {
+
+    /* FIXME: Assuming mimetype of "audio/L16;rate=44100,channels=2" */
+
+    /* Init stream data */
+    stream->blob_handler = guac_rdp_audio_blob_handler;
+    stream->end_handler = guac_rdp_audio_end_handler;
+
+    guac_protocol_send_ack(user->socket, stream,
+            "OK", GUAC_PROTOCOL_STATUS_SUCCESS);
+    guac_socket_flush(user->socket);
+
+    return 0;
+
+}
+
+int guac_rdp_audio_blob_handler(guac_user* user, guac_stream* stream,
+        void* data, int length) {
+
+    /* STUB */
+    return 0;
+
+}
+
+int guac_rdp_audio_end_handler(guac_user* user, guac_stream* stream) {
+
+    /* STUB */
+    return 0;
+
+}
+
+void guac_rdp_audio_load_plugin(rdpContext* context) {
+
+    /* Add "AUDIO_INPUT" channel */
+    ADDIN_ARGV* args = malloc(sizeof(ADDIN_ARGV));
+    args->argc = 1;
+    args->argv = malloc(sizeof(char**) * 1);
+    args->argv[0] = strdup("guacai");
+    freerdp_dynamic_channel_collection_add(context->settings, args);
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/21ab9d76/src/protocols/rdp/audio_input.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/audio_input.h b/src/protocols/rdp/audio_input.h
new file mode 100644
index 0000000..d32cda1
--- /dev/null
+++ b/src/protocols/rdp/audio_input.h
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 GUAC_RDP_AUDIO_INPUT_H
+#define GUAC_RDP_AUDIO_INPUT_H
+
+#include "config.h"
+
+#include <freerdp/freerdp.h>
+#include <guacamole/user.h>
+
+/**
+ * Handler for inbound audio data (audio input).
+ */
+guac_user_audio_handler guac_rdp_audio_handler;
+
+/**
+ * Handler for stream data related to audio input.
+ */
+guac_user_blob_handler guac_rdp_audio_blob_handler;
+
+/**
+ * Handler for end-of-stream related to audio input.
+ */
+guac_user_end_handler guac_rdp_audio_end_handler;
+
+/**
+ * Loads Guacamole's "guacai" plugin for FreeRDP, adding support for the
+ * "AUDIO_INPUT" dynamic virtual channel. This function must ONLY be called
+ * after FreeRDP's "drdynvc" virtual channel plugin has been loaded.
+ *
+ * @param context
+ *     The rdpContext associated with the active RDP session.
+ */
+void guac_rdp_audio_load_plugin(rdpContext* context);
+
+#endif
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/21ab9d76/src/protocols/rdp/guac_ai/ai_service.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/guac_ai/ai_service.c b/src/protocols/rdp/guac_ai/ai_service.c
new file mode 100644
index 0000000..15490a0
--- /dev/null
+++ b/src/protocols/rdp/guac_ai/ai_service.c
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "config.h"
+
+#include "ai_service.h"
+#include "rdp.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <freerdp/freerdp.h>
+#include <freerdp/constants.h>
+#include <freerdp/dvc.h>
+#include <guacamole/client.h>
+
+#ifdef ENABLE_WINPR
+#include <winpr/stream.h>
+#else
+#include "compat/winpr-stream.h"
+#endif
+
+/**
+ * Entry point for AUDIO_INPUT dynamic virtual channel.
+ */
+int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) {
+
+    rdpSettings* settings = pEntryPoints->GetRdpSettings(pEntryPoints);
+    freerdp* instance = settings->instance;
+    rdpContext* context = instance->context;
+    guac_client* client = ((rdp_freerdp_context*) context)->client;
+
+    /* STUB */
+    guac_client_log(client, GUAC_LOG_DEBUG,
+            "STUB: AUDIO_INPUT DVC (entry point)");
+
+    return 1;
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/21ab9d76/src/protocols/rdp/guac_ai/ai_service.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/guac_ai/ai_service.h b/src/protocols/rdp/guac_ai/ai_service.h
new file mode 100644
index 0000000..caa62ad
--- /dev/null
+++ b/src/protocols/rdp/guac_ai/ai_service.h
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 GUAC_RDP_AI_SERVICE_H
+#define GUAC_RDP_AI_SERVICE_H
+
+#include "config.h"
+
+/* STUB */
+
+#endif
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/21ab9d76/src/protocols/rdp/rdp.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c
index cd3ee23..7859e20 100644
--- a/src/protocols/rdp/rdp.c
+++ b/src/protocols/rdp/rdp.c
@@ -19,6 +19,7 @@
 
 #include "config.h"
 
+#include "audio_input.h"
 #include "client.h"
 #include "guac_cursor.h"
 #include "guac_display.h"
@@ -223,24 +224,33 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
             (pChannelConnectedEventHandler) guac_rdp_channel_connected);
 #endif
 
-#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
-    /* Load required plugins if display update is enabled */
-    if (settings->resize_method == GUAC_RESIZE_DISPLAY_UPDATE) {
+    /* Load DRDYNVC plugin if required */
+    if (settings->resize_method == GUAC_RESIZE_DISPLAY_UPDATE
+            || settings->enable_audio_input) {
 
-        /* Load virtual channel management plugin (needed by display update) */
+        /* Load virtual channel management plugin */
         if (freerdp_channels_load_plugin(channels, instance->settings,
                     "drdynvc", instance->settings))
             guac_client_log(client, GUAC_LOG_WARNING,
-                    "Failed to load drdynvc plugin. Display update support "
-                    "will be disabled.");
+                    "Failed to load drdynvc plugin. Display update and audio "
+                    "input support will be disabled.");
 
         /* Init display update plugin if "drdynvc" was loaded successfully */
-        else
-            guac_rdp_disp_load_plugin(instance->context);
-
-    }
+        else {
+#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
+            /* Load "disp" plugin for display update */
+            if (settings->resize_method == GUAC_RESIZE_DISPLAY_UPDATE)
+                guac_rdp_disp_load_plugin(instance->context);
 #endif
 
+            /* Load "AUDIO_INPUT" plugin for audio input*/
+            if (settings->enable_audio_input)
+                guac_rdp_audio_load_plugin(instance->context);
+
+        }
+
+    } /* end if drdynvc required */
+
     /* Load clipboard plugin */
     if (freerdp_channels_load_plugin(channels, instance->settings,
                 "cliprdr", NULL))

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/21ab9d76/src/protocols/rdp/rdp_settings.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/rdp_settings.c b/src/protocols/rdp/rdp_settings.c
index bc1d831..4f9343c 100644
--- a/src/protocols/rdp/rdp_settings.c
+++ b/src/protocols/rdp/rdp_settings.c
@@ -90,6 +90,7 @@ const char* GUAC_RDP_CLIENT_ARGS[] = {
     "recording-name",
     "create-recording-path",
     "resize-method",
+    "enable-audio-input",
 
     NULL
 };
@@ -378,6 +379,12 @@ enum RDP_ARGS_IDX {
      */
     IDX_RESIZE_METHOD,
 
+    /**
+     * "true" if audio input (microphone) should be enabled for the RDP
+     * connection, "false" or blank otherwise.
+     */
+    IDX_ENABLE_AUDIO_INPUT,
+
     RDP_ARGS_COUNT
 };
 
@@ -739,6 +746,11 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user,
         settings->resize_method = GUAC_RESIZE_NONE;
     }
 
+    /* Audio input enable/disable */
+    settings->enable_audio_input =
+        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
+                IDX_ENABLE_AUDIO_INPUT, 0);
+
     /* Success */
     return settings;
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/21ab9d76/src/protocols/rdp/rdp_settings.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/rdp_settings.h b/src/protocols/rdp/rdp_settings.h
index 7e3fec9..90c79ce 100644
--- a/src/protocols/rdp/rdp_settings.h
+++ b/src/protocols/rdp/rdp_settings.h
@@ -378,6 +378,11 @@ typedef struct guac_rdp_settings {
      */
     guac_rdp_resize_method resize_method;
 
+    /**
+     * Whether audio input (microphone) is enabled.
+     */
+    int enable_audio_input;
+
 } guac_rdp_settings;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/21ab9d76/src/protocols/rdp/user.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/user.c b/src/protocols/rdp/user.c
index af597db..ef13205 100644
--- a/src/protocols/rdp/user.c
+++ b/src/protocols/rdp/user.c
@@ -19,6 +19,7 @@
 
 #include "config.h"
 
+#include "audio_input.h"
 #include "input.h"
 #include "guac_display.h"
 #include "user.h"
@@ -65,6 +66,10 @@ int guac_rdp_user_join_handler(guac_user* user, int argc, char** argv) {
             return 1;
         }
 
+        /* Handle inbound audio streams if audio input is enabled */
+        if (settings->enable_audio_input)
+            user->audio_handler = guac_rdp_audio_handler;
+
     }
 
     /* If not owner, synchronize with current state */


[03/26] incubator-guacamole-server git commit: GUACAMOLE-25: Add status code reporting the normal closure of a resource.

Posted by jm...@apache.org.
GUACAMOLE-25: Add status code reporting the normal closure of a resource.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/5030c060
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/5030c060
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/5030c060

Branch: refs/heads/master
Commit: 5030c0603a9d8aa4a65c31afcb20e50ca71136f4
Parents: 166eba1
Author: Michael Jumper <mj...@apache.org>
Authored: Mon May 2 00:09:17 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed May 25 13:50:28 2016 -0700

----------------------------------------------------------------------
 src/libguac/guacamole/protocol-types.h | 6 ++++++
 1 file changed, 6 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/5030c060/src/libguac/guacamole/protocol-types.h
----------------------------------------------------------------------
diff --git a/src/libguac/guacamole/protocol-types.h b/src/libguac/guacamole/protocol-types.h
index ee9c668..ea76910 100644
--- a/src/libguac/guacamole/protocol-types.h
+++ b/src/libguac/guacamole/protocol-types.h
@@ -88,6 +88,12 @@ typedef enum guac_protocol_status {
     GUAC_PROTOCOL_STATUS_RESOURCE_CONFLICT = 0x205,
 
     /**
+     * The operation could not be performed as the requested resource is now
+     * closed.
+     */
+    GUAC_PROTOCOL_STATUS_RESOURCE_CLOSED = 0x0206,
+
+    /**
      * The operation could not be performed because bad parameters were
      * given.
      */


[26/26] incubator-guacamole-server git commit: GUACAMOLE-25: Merge RDP audio input addition."

Posted by jm...@apache.org.
GUACAMOLE-25: Merge RDP audio input addition."


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/995b6d66
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/995b6d66
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/995b6d66

Branch: refs/heads/master
Commit: 995b6d669ac4bfd620aa5fe123c6dc4212956e28
Parents: ec93a29 402b039
Author: James Muehlner <ja...@guac-dev.org>
Authored: Thu Jun 2 11:44:16 2016 -0700
Committer: James Muehlner <ja...@guac-dev.org>
Committed: Thu Jun 2 11:44:16 2016 -0700

----------------------------------------------------------------------
 configure.ac                            |  47 +++
 src/libguac/guacamole/protocol-types.h  |   6 +
 src/protocols/rdp/Makefile.am           |  46 +++
 src/protocols/rdp/audio_input.c         | 484 +++++++++++++++++++++++++++
 src/protocols/rdp/audio_input.h         | 313 +++++++++++++++++
 src/protocols/rdp/client.c              |   5 +
 src/protocols/rdp/compat/winpr-stream.c |  23 +-
 src/protocols/rdp/dvc.c                 | 183 ++++++++++
 src/protocols/rdp/dvc.h                 | 138 ++++++++
 src/protocols/rdp/guac_ai/ai_messages.c | 336 +++++++++++++++++++
 src/protocols/rdp/guac_ai/ai_messages.h | 216 ++++++++++++
 src/protocols/rdp/guac_ai/ai_service.c  | 349 +++++++++++++++++++
 src/protocols/rdp/guac_ai/ai_service.h  | 108 ++++++
 src/protocols/rdp/ptr_string.c          |  55 +++
 src/protocols/rdp/ptr_string.h          |  57 ++++
 src/protocols/rdp/rdp.c                 |  34 +-
 src/protocols/rdp/rdp.h                 |   6 +
 src/protocols/rdp/rdp_disp.c            |  11 +-
 src/protocols/rdp/rdp_disp.h            |  23 +-
 src/protocols/rdp/rdp_settings.c        |  23 ++
 src/protocols/rdp/rdp_settings.h        |   5 +
 src/protocols/rdp/user.c                |   5 +
 22 files changed, 2439 insertions(+), 34 deletions(-)
----------------------------------------------------------------------