From a9a823b0dae106d2a73178ca8074632795c4afc9 Mon Sep 17 00:00:00 2001 From: Jay Sorg Date: Thu, 4 Jul 2019 23:52:18 -0700 Subject: [PATCH] chansrv: audio in partial working --- sesman/chansrv/audin.c | 369 ++++++++++++++++++++++++++++++++++++++++- sesman/chansrv/audin.h | 3 + 2 files changed, 363 insertions(+), 9 deletions(-) diff --git a/sesman/chansrv/audin.c b/sesman/chansrv/audin.c index 17629010..98eda69e 100644 --- a/sesman/chansrv/audin.c +++ b/sesman/chansrv/audin.c @@ -14,6 +14,9 @@ * 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. + * + * MS-RDPEAI + * */ #if defined(HAVE_CONFIG_H) @@ -27,27 +30,328 @@ #include "os_calls.h" #include "chansrv.h" #include "log.h" +#include "xrdp_constants.h" + +#define MSG_SNDIN_VERSION 1 +#define MSG_SNDIN_FORMATS 2 +#define MSG_SNDIN_OPEN 3 +#define MSG_SNDIN_OPEN_REPLY 4 +#define MSG_SNDIN_DATA_INCOMING 5 +#define MSG_SNDIN_DATA 6 +#define MSG_SNDIN_FORMATCHANGE 7 + +#define AUDIN_VERSION 0x00000001 + +#define AUDIN_NAME "AUDIO_INPUT" +#define AUDIN_FLAGS 1 /* WTS_CHANNEL_OPTION_DYNAMIC */ + +struct xr_wave_format_ex +{ + int wFormatTag; + int nChannels; + int nSamplesPerSec; + int nAvgBytesPerSec; + int nBlockAlign; + int wBitsPerSample; + int cbSize; + uint8_t *data; +}; + +static uint8_t g_pcm_44100_data[] = { 0 }; +static struct xr_wave_format_ex g_pcm_44100 = +{ + WAVE_FORMAT_PCM, /* wFormatTag */ + 2, /* num of channels */ + 44100, /* samples per sec */ + 176400, /* avg bytes per sec */ + 4, /* block align */ + 16, /* bits per sample */ + 0, /* data size */ + g_pcm_44100_data /* data */ +}; static struct chansrv_drdynvc_procs g_audin_info; -static int g_audio_chanid = 0; +static int g_audio_chanid; +static struct stream *g_in_s; + +static struct xr_wave_format_ex *g_server_formats[] = +{ + &g_pcm_44100, + NULL +}; + +static struct xr_wave_format_ex **g_client_formats = NULL; + +static int g_current_format = 0; /* index in g_client_formats */ + +/*****************************************************************************/ +static int +cleanup_client_formats(void) +{ + int index; + + if (g_client_formats == NULL) + { + return 0; + } + index = 0; + while (g_client_formats[index] != NULL) + { + g_free(g_client_formats[index]->data); + g_free(g_client_formats[index]); + } + g_free(g_client_formats); + g_client_formats = NULL; + return 0; +} /*****************************************************************************/ static int audio_send_version(int chan_id) { int error; + int bytes; struct stream *s; LOG(0, ("audio_send_version:")); make_stream(s); init_stream(s, 32); - out_uint8(s, 1); /* MSG_SNDIN_VERSION */ - out_uint32_le(s, 1); /* version */ - error = chansrv_drdynvc_data(chan_id, s->data, 5); + out_uint8(s, MSG_SNDIN_VERSION); + out_uint32_le(s, AUDIN_VERSION); + s_mark_end(s); + bytes = (int) (s->end - s->data); + error = chansrv_drdynvc_data(chan_id, s->data, bytes); free_stream(s); return error; } +/*****************************************************************************/ +static int +audio_send_formats(int chan_id) +{ + int error; + int bytes; + int num_formats; + int index; + struct stream *s; + struct xr_wave_format_ex *wf; + + LOG(0, ("audio_send_formats:")); + num_formats = sizeof(g_server_formats) / + sizeof(g_server_formats[0]) - 1; + make_stream(s); + init_stream(s, 8192 * num_formats); + out_uint8(s, MSG_SNDIN_FORMATS); + out_uint32_le(s, num_formats); + out_uint32_le(s, 0); /* cbSizeFormatsPacket */ + for (index = 0; index < num_formats; index++) + { + wf = g_server_formats[index]; + out_uint16_le(s, wf->wFormatTag); + out_uint16_le(s, wf->nChannels); + out_uint32_le(s, wf->nSamplesPerSec); + out_uint32_le(s, wf->nAvgBytesPerSec); + out_uint16_le(s, wf->nBlockAlign); + out_uint16_le(s, wf->wBitsPerSample); + bytes = wf->cbSize; + out_uint16_le(s, bytes); + if (bytes > 0) + { + out_uint8p(s, wf->data, bytes); + } + } + s_mark_end(s); + bytes = (int) (s->end - s->data); + error = chansrv_drdynvc_data(chan_id, s->data, bytes); + free_stream(s); + return error; +} + +/*****************************************************************************/ +static int +audio_send_open(int chan_id) +{ + int error; + int bytes; + struct stream *s; + struct xr_wave_format_ex *wf; + + LOG(0, ("audio_send_open:")); + make_stream(s); + init_stream(s, 8192); + out_uint8(s, MSG_SNDIN_OPEN); + out_uint32_le(s, 2048); /* FramesPerPacket */ + out_uint32_le(s, g_current_format); /* initialFormat */ + wf = g_client_formats[g_current_format]; + out_uint16_le(s, wf->wFormatTag); + out_uint16_le(s, wf->nChannels); + out_uint32_le(s, wf->nSamplesPerSec); + out_uint32_le(s, wf->nAvgBytesPerSec); + out_uint16_le(s, wf->nBlockAlign); + out_uint16_le(s, wf->wBitsPerSample); + bytes = wf->cbSize; + out_uint16_le(s, bytes); + if (bytes > 0) + { + out_uint8p(s, wf->data, bytes); + } + s_mark_end(s); + bytes = (int) (s->end - s->data); + error = chansrv_drdynvc_data(chan_id, s->data, bytes); + free_stream(s); + return error; +} + +/*****************************************************************************/ +static int +audin_process_version(int chan_id, struct stream *s) +{ + int version; + + LOG(0, ("audin_process_version:")); + if (!s_check_rem(s, 4)) + { + LOG(0, ("audin_process_version: parse error")); + return 1; + } + in_uint32_le(s, version); + LOG(0, ("audin_process_version: version %d", version)); + return audio_send_formats(chan_id); +} + +/*****************************************************************************/ +static int +audin_process_formats(int chan_id, struct stream *s) +{ + int index; + int num_formats; + struct xr_wave_format_ex *wf; + + LOG(0, ("audin_process_formats:")); + cleanup_client_formats(); + if (!s_check_rem(s, 8)) + { + LOG(0, ("audin_process_formats: parse error")); + return 1; + } + in_uint32_le(s, num_formats); + in_uint8s(s, 4); /* cbSizeFormatsPacket */ + g_client_formats = g_new0(struct xr_wave_format_ex *, num_formats + 1); + for (index = 0; index < num_formats; index++) + { + if (!s_check_rem(s, 18)) + { + LOG(0, ("audin_process_formats: parse error")); + return 1; + } + wf = g_new0(struct xr_wave_format_ex, 1); + g_client_formats[index] = wf; + in_uint16_le(s, wf->wFormatTag); + in_uint16_le(s, wf->nChannels); + in_uint32_le(s, wf->nSamplesPerSec); + in_uint32_le(s, wf->nAvgBytesPerSec); + in_uint16_le(s, wf->nBlockAlign); + in_uint16_le(s, wf->wBitsPerSample); + in_uint16_le(s, wf->cbSize); + if (wf->cbSize > 0) + { + if (!s_check_rem(s, wf->cbSize)) + { + LOG(0, ("audin_process_formats: parse error")); + return 1; + } + wf->data = g_new0(uint8_t, wf->cbSize); + in_uint8a(s, wf->data, wf->cbSize); + } + } + audio_send_open(chan_id); + return 0; +} + +/*****************************************************************************/ +static int +audin_process_open_reply(int chan_id, struct stream *s) +{ + int result; + + if (!s_check_rem(s, 4)) + { + LOG(0, ("audin_process_open_reply: parse error")); + return 1; + } + in_uint32_le(s, result); + LOG(0, ("audin_process_open_reply: result %d", result)); + return 0; +} + +/*****************************************************************************/ +static int +audin_process_incoming_data(int chan_id, struct stream *s) +{ + LOG(0, ("audin_process_incoming_data:")); + return 0; +} + +/*****************************************************************************/ +static int +audin_process_data(int chan_id, struct stream *s) +{ + int data_bytes; + + data_bytes = (int) (s->end - s->p); + LOG(0, ("audin_process_data: data_bytes %d", data_bytes)); + return 0; +} + +/*****************************************************************************/ +static int +audin_process_format_change(int chan_id, struct stream *s) +{ + LOG(0, ("audin_process_format_change:")); + if (!s_check_rem(s, 4)) + { + LOG(0, ("audin_process_format_change: parse error")); + return 1; + } + in_uint32_le(s, g_current_format); + return 0; +} + +/*****************************************************************************/ +static int +audin_process_msg(int chan_id, struct stream *s) +{ + int code; + + LOG(0, ("audin_process_msg:")); + if (!s_check_rem(s, 1)) + { + LOG(0, ("audin_process_msg: parse error")); + return 1; + } + in_uint8(s, code); + LOG(0, ("audin_process_msg: code %d", code)); + switch (code) + { + case MSG_SNDIN_VERSION: + return audin_process_version(chan_id, s); + case MSG_SNDIN_FORMATS: + return audin_process_formats(chan_id, s); + case MSG_SNDIN_OPEN_REPLY: + return audin_process_open_reply(chan_id, s); + case MSG_SNDIN_DATA_INCOMING: + return audin_process_incoming_data(chan_id, s); + case MSG_SNDIN_DATA: + return audin_process_data(chan_id, s); + case MSG_SNDIN_FORMATCHANGE: + return audin_process_format_change(chan_id, s); + default: + LOG(0, ("audin_process_msg: unprocessed code %d", code)); + break; + } + return 0; +} + /*****************************************************************************/ static int audin_open_response(int chan_id, int creation_status) @@ -68,21 +372,65 @@ audin_close_response(int chan_id) return 0; } +/*****************************************************************************/ +static int +audin_data_fragment(int chan_id, char *data, int bytes) +{ + int rv; + int left; + + LOG(0, ("audin_data_fragment:")); + if (!s_check_rem(g_in_s, bytes)) + { + left = (int) (g_in_s->end - g_in_s->p); + LOG(0, ("audin_data_fragment: error bytes %d left %d", bytes, left)); + return 1; + } + out_uint8a(g_in_s, data, bytes); + if (g_in_s->p == g_in_s->end) + { + g_in_s->p = g_in_s->data; + rv = audin_process_msg(chan_id, g_in_s); + free_stream(g_in_s); + g_in_s = NULL; + return rv; + } + return 0; +} + /*****************************************************************************/ static int audin_data_first(int chan_id, char *data, int bytes, int total_bytes) { LOG(0, ("audin_data_first:")); - return 0; + if (g_in_s != NULL) + { + LOG(0, ("audin_data_first: warning g_in_s is not nil")); + free_stream(g_in_s); + } + make_stream(g_in_s); + init_stream(g_in_s, total_bytes); + g_in_s->end = g_in_s->data + total_bytes; + return audin_data_fragment(chan_id, data, bytes); } /*****************************************************************************/ static int audin_data(int chan_id, char *data, int bytes) { + struct stream ls; + LOG(0, ("audin_data:")); - g_hexdump(data, bytes); - return 0; + //g_hexdump(data, bytes); + if (g_in_s == NULL) + { + g_memset(&ls, 0, sizeof(ls)); + ls.data = data; + ls.p = ls.data; + ls.end = ls.p + bytes; + return audin_process_msg(chan_id, &ls); + } + return audin_data_fragment(chan_id, data, bytes); } /*****************************************************************************/ @@ -97,8 +445,11 @@ audin_init(void) g_audin_info.close_response = audin_close_response; g_audin_info.data_first = audin_data_first; g_audin_info.data = audin_data; - error = chansrv_drdynvc_open("AUDIO_INPUT", 1, &g_audin_info, - &g_audio_chanid); + g_audio_chanid = 0; + g_in_s = NULL; + error = chansrv_drdynvc_open(AUDIN_NAME, AUDIN_FLAGS, + &g_audin_info, /* callback functions */ + &g_audio_chanid); /* chansrv chan_id */ LOG(0, ("audin_init: error %d", error)); return error; } diff --git a/sesman/chansrv/audin.h b/sesman/chansrv/audin.h index 17cf6f8f..d13efd08 100644 --- a/sesman/chansrv/audin.h +++ b/sesman/chansrv/audin.h @@ -14,6 +14,9 @@ * 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. + * + * MS-RDPEAI + * */ #ifndef _AUDIN_H_