1 /**
2 * xrdp: A Remote Desktop Protocol server.
3 *
4 * Copyright (C) Jay Sorg 2019
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * MS-RDPEAI
19 *
20 */
21
22 #if defined(HAVE_CONFIG_H)
23 #include <config_ac.h>
24 #endif
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "os_calls.h"
31 #include "chansrv.h"
32 #include "log.h"
33 #include "xrdp_constants.h"
34 #include "fifo.h"
35
36 #define MSG_SNDIN_VERSION 1
37 #define MSG_SNDIN_FORMATS 2
38 #define MSG_SNDIN_OPEN 3
39 #define MSG_SNDIN_OPEN_REPLY 4
40 #define MSG_SNDIN_DATA_INCOMING 5
41 #define MSG_SNDIN_DATA 6
42 #define MSG_SNDIN_FORMATCHANGE 7
43
44 #define AUDIN_VERSION 0x00000001
45
46 #define AUDIN_NAME "AUDIO_INPUT"
47 #define AUDIN_FLAGS 1 /* WTS_CHANNEL_OPTION_DYNAMIC */
48
49 extern FIFO g_in_fifo; /* in sound.c */
50 extern int g_bytes_in_fifo; /* in sound.c */
51
52 struct xr_wave_format_ex
53 {
54 int wFormatTag;
55 int nChannels;
56 int nSamplesPerSec;
57 int nAvgBytesPerSec;
58 int nBlockAlign;
59 int wBitsPerSample;
60 int cbSize;
61 uint8_t *data;
62 };
63
64 static uint8_t g_pcm_44100_data[] = { 0 };
65 static struct xr_wave_format_ex g_pcm_44100 =
66 {
67 WAVE_FORMAT_PCM, /* wFormatTag */
68 2, /* num of channels */
69 44100, /* samples per sec */
70 176400, /* avg bytes per sec */
71 4, /* block align */
72 16, /* bits per sample */
73 0, /* data size */
74 g_pcm_44100_data /* data */
75 };
76
77 static struct chansrv_drdynvc_procs g_audin_info;
78 static int g_audin_chanid;
79 static struct stream *g_in_s;
80
81 static struct xr_wave_format_ex *g_server_formats[] =
82 {
83 &g_pcm_44100,
84 NULL
85 };
86
87 static struct xr_wave_format_ex **g_client_formats = NULL;
88
89 static int g_current_format = 0; /* index in g_client_formats */
90
91 /*****************************************************************************/
92 static int
cleanup_client_formats(void)93 cleanup_client_formats(void)
94 {
95 int index;
96
97 if (g_client_formats == NULL)
98 {
99 return 0;
100 }
101 index = 0;
102 while (g_client_formats[index] != NULL)
103 {
104 g_free(g_client_formats[index]->data);
105 g_free(g_client_formats[index]);
106 index++;
107 }
108 g_free(g_client_formats);
109 g_client_formats = NULL;
110 return 0;
111 }
112
113 /*****************************************************************************/
114 static int
audin_send_version(int chan_id)115 audin_send_version(int chan_id)
116 {
117 int error;
118 int bytes;
119 struct stream *s;
120
121 LOG_DEVEL(LOG_LEVEL_INFO, "audin_send_version:");
122 make_stream(s);
123 init_stream(s, 32);
124 out_uint8(s, MSG_SNDIN_VERSION);
125 out_uint32_le(s, AUDIN_VERSION);
126 s_mark_end(s);
127 bytes = (int) (s->end - s->data);
128 error = chansrv_drdynvc_data(chan_id, s->data, bytes);
129 free_stream(s);
130 return error;
131 }
132
133 /*****************************************************************************/
134 static int
audin_send_formats(int chan_id)135 audin_send_formats(int chan_id)
136 {
137 int error;
138 int bytes;
139 int num_formats;
140 int index;
141 struct stream *s;
142 struct xr_wave_format_ex *wf;
143
144 LOG_DEVEL(LOG_LEVEL_INFO, "audin_send_formats:");
145 num_formats = sizeof(g_server_formats) /
146 sizeof(g_server_formats[0]) - 1;
147 make_stream(s);
148 init_stream(s, 8192 * num_formats);
149 out_uint8(s, MSG_SNDIN_FORMATS);
150 out_uint32_le(s, num_formats);
151 out_uint32_le(s, 0); /* cbSizeFormatsPacket */
152 for (index = 0; index < num_formats; index++)
153 {
154 wf = g_server_formats[index];
155 LOG_DEVEL(LOG_LEVEL_INFO, "audin_send_formats: sending format wFormatTag 0x%4.4x "
156 "nChannels %d nSamplesPerSec %d",
157 wf->wFormatTag, wf->nChannels, wf->nSamplesPerSec);
158 out_uint16_le(s, wf->wFormatTag);
159 out_uint16_le(s, wf->nChannels);
160 out_uint32_le(s, wf->nSamplesPerSec);
161 out_uint32_le(s, wf->nAvgBytesPerSec);
162 out_uint16_le(s, wf->nBlockAlign);
163 out_uint16_le(s, wf->wBitsPerSample);
164 out_uint16_le(s, wf->cbSize);
165 if (wf->cbSize > 0)
166 {
167 out_uint8p(s, wf->data, wf->cbSize);
168 }
169 }
170 s_mark_end(s);
171 bytes = (int) (s->end - s->data);
172 error = chansrv_drdynvc_data(chan_id, s->data, bytes);
173 free_stream(s);
174 return error;
175 }
176
177 /*****************************************************************************/
178 static int
audin_send_open(int chan_id)179 audin_send_open(int chan_id)
180 {
181 int error;
182 int bytes;
183 struct stream *s;
184 struct xr_wave_format_ex *wf;
185
186 LOG_DEVEL(LOG_LEVEL_INFO, "audin_send_open:");
187 make_stream(s);
188 init_stream(s, 8192);
189 out_uint8(s, MSG_SNDIN_OPEN);
190 out_uint32_le(s, 2048); /* FramesPerPacket */
191 out_uint32_le(s, g_current_format); /* initialFormat */
192 wf = g_client_formats[g_current_format];
193 out_uint16_le(s, wf->wFormatTag);
194 out_uint16_le(s, wf->nChannels);
195 out_uint32_le(s, wf->nSamplesPerSec);
196 out_uint32_le(s, wf->nAvgBytesPerSec);
197 out_uint16_le(s, wf->nBlockAlign);
198 out_uint16_le(s, wf->wBitsPerSample);
199 bytes = wf->cbSize;
200 out_uint16_le(s, bytes);
201 if (bytes > 0)
202 {
203 out_uint8p(s, wf->data, bytes);
204 }
205 s_mark_end(s);
206 bytes = (int) (s->end - s->data);
207 error = chansrv_drdynvc_data(chan_id, s->data, bytes);
208 free_stream(s);
209 return error;
210 }
211
212 /*****************************************************************************/
213 static int
audin_process_version(int chan_id,struct stream * s)214 audin_process_version(int chan_id, struct stream *s)
215 {
216 int version;
217
218 LOG_DEVEL(LOG_LEVEL_INFO, "audin_process_version:");
219 if (!s_check_rem(s, 4))
220 {
221 LOG_DEVEL(LOG_LEVEL_ERROR, "audin_process_version: parse error");
222 return 1;
223 }
224 in_uint32_le(s, version);
225 LOG(LOG_LEVEL_INFO, "audin_process_version: version %d", version);
226 return audin_send_formats(chan_id);
227 }
228
229 /*****************************************************************************/
230 static int
audin_process_formats(int chan_id,struct stream * s)231 audin_process_formats(int chan_id, struct stream *s)
232 {
233 int index;
234 int num_formats;
235 struct xr_wave_format_ex *wf;
236
237 LOG_DEVEL(LOG_LEVEL_INFO, "audin_process_formats:");
238 cleanup_client_formats();
239 if (!s_check_rem(s, 8))
240 {
241 LOG_DEVEL(LOG_LEVEL_ERROR, "audin_process_formats: parse error");
242 return 1;
243 }
244 in_uint32_le(s, num_formats);
245 in_uint8s(s, 4); /* cbSizeFormatsPacket */
246 g_client_formats = g_new0(struct xr_wave_format_ex *, num_formats + 1);
247 for (index = 0; index < num_formats; index++)
248 {
249 if (!s_check_rem(s, 18))
250 {
251 LOG_DEVEL(LOG_LEVEL_ERROR, "audin_process_formats: parse error");
252 return 1;
253 }
254 wf = g_new0(struct xr_wave_format_ex, 1);
255 g_client_formats[index] = wf;
256 in_uint16_le(s, wf->wFormatTag);
257 in_uint16_le(s, wf->nChannels);
258 in_uint32_le(s, wf->nSamplesPerSec);
259 in_uint32_le(s, wf->nAvgBytesPerSec);
260 in_uint16_le(s, wf->nBlockAlign);
261 in_uint16_le(s, wf->wBitsPerSample);
262 in_uint16_le(s, wf->cbSize);
263 LOG_DEVEL(LOG_LEVEL_INFO, "audin_process_formats: recved format wFormatTag 0x%4.4x "
264 "nChannels %d nSamplesPerSec %d",
265 wf->wFormatTag, wf->nChannels, wf->nSamplesPerSec);
266 if (wf->cbSize > 0)
267 {
268 if (!s_check_rem(s, wf->cbSize))
269 {
270 LOG_DEVEL(LOG_LEVEL_ERROR, "audin_process_formats: parse error");
271 return 1;
272 }
273 wf->data = g_new0(uint8_t, wf->cbSize);
274 in_uint8a(s, wf->data, wf->cbSize);
275 }
276 }
277 audin_send_open(chan_id);
278 return 0;
279 }
280
281 /*****************************************************************************/
282 static int
audin_process_open_reply(int chan_id,struct stream * s)283 audin_process_open_reply(int chan_id, struct stream *s)
284 {
285 int result;
286
287 if (!s_check_rem(s, 4))
288 {
289 LOG_DEVEL(LOG_LEVEL_ERROR, "audin_process_open_reply: parse error");
290 return 1;
291 }
292 in_uint32_le(s, result);
293 LOG(LOG_LEVEL_INFO, "audin_process_open_reply: result 0x%8.8x", result);
294 return 0;
295 }
296
297 /*****************************************************************************/
298 static int
audin_process_incoming_data(int chan_id,struct stream * s)299 audin_process_incoming_data(int chan_id, struct stream *s)
300 {
301 LOG_DEVEL(LOG_LEVEL_DEBUG, "audin_process_incoming_data:");
302 return 0;
303 }
304
305 /*****************************************************************************/
306 static int
audin_process_data(int chan_id,struct stream * s)307 audin_process_data(int chan_id, struct stream *s)
308 {
309 int data_bytes;
310 struct stream *ls;
311
312 data_bytes = (int) (s->end - s->p);
313 LOG_DEVEL(LOG_LEVEL_DEBUG, "audin_process_data: data_bytes %d", data_bytes);
314
315 xstream_new(ls, data_bytes);
316 g_memcpy(ls->data, s->p, data_bytes);
317 ls->p += data_bytes;
318 s_mark_end(ls);
319 fifo_insert(&g_in_fifo, (void *) ls);
320 g_bytes_in_fifo += data_bytes;
321
322 return 0;
323 }
324
325 /*****************************************************************************/
326 static int
audin_process_format_change(int chan_id,struct stream * s)327 audin_process_format_change(int chan_id, struct stream *s)
328 {
329 LOG_DEVEL(LOG_LEVEL_INFO, "audin_process_format_change:");
330 if (!s_check_rem(s, 4))
331 {
332 LOG_DEVEL(LOG_LEVEL_ERROR, "audin_process_format_change: parse error");
333 return 1;
334 }
335 in_uint32_le(s, g_current_format);
336 LOG_DEVEL(LOG_LEVEL_INFO, "audin_process_format_change: g_current_format %d",
337 g_current_format);
338 return 0;
339 }
340
341 /*****************************************************************************/
342 static int
audin_process_msg(int chan_id,struct stream * s)343 audin_process_msg(int chan_id, struct stream *s)
344 {
345 int code;
346
347 LOG_DEVEL(LOG_LEVEL_DEBUG, "audin_process_msg:");
348 if (!s_check_rem(s, 1))
349 {
350 LOG_DEVEL(LOG_LEVEL_ERROR, "audin_process_msg: parse error");
351 return 1;
352 }
353 in_uint8(s, code);
354 LOG_DEVEL(LOG_LEVEL_DEBUG, "audin_process_msg: code %d", code);
355 switch (code)
356 {
357 case MSG_SNDIN_VERSION:
358 return audin_process_version(chan_id, s);
359 case MSG_SNDIN_FORMATS:
360 return audin_process_formats(chan_id, s);
361 case MSG_SNDIN_OPEN_REPLY:
362 return audin_process_open_reply(chan_id, s);
363 case MSG_SNDIN_DATA_INCOMING:
364 return audin_process_incoming_data(chan_id, s);
365 case MSG_SNDIN_DATA:
366 return audin_process_data(chan_id, s);
367 case MSG_SNDIN_FORMATCHANGE:
368 return audin_process_format_change(chan_id, s);
369 default:
370 LOG_DEVEL(LOG_LEVEL_ERROR, "audin_process_msg: unprocessed code %d", code);
371 break;
372 }
373 return 0;
374 }
375
376 /*****************************************************************************/
377 static int
audin_open_response(int chan_id,int creation_status)378 audin_open_response(int chan_id, int creation_status)
379 {
380 LOG_DEVEL(LOG_LEVEL_INFO, "audin_open_response: creation_status 0x%8.8x", creation_status);
381 if (creation_status == 0)
382 {
383 return audin_send_version(chan_id);
384 }
385 return 0;
386 }
387
388 /*****************************************************************************/
389 static int
audin_close_response(int chan_id)390 audin_close_response(int chan_id)
391 {
392 LOG_DEVEL(LOG_LEVEL_INFO, "audin_close_response:");
393 g_audin_chanid = 0;
394 cleanup_client_formats();
395 free_stream(g_in_s);
396 g_in_s = NULL;
397 return 0;
398 }
399
400 /*****************************************************************************/
401 static int
audin_data_fragment(int chan_id,char * data,int bytes)402 audin_data_fragment(int chan_id, char *data, int bytes)
403 {
404 int rv;
405
406 LOG_DEVEL(LOG_LEVEL_DEBUG, "audin_data_fragment:");
407 if (!s_check_rem(g_in_s, bytes))
408 {
409 LOG_DEVEL(LOG_LEVEL_ERROR, "audin_data_fragment: error bytes %d left %d",
410 bytes, (int) (g_in_s->end - g_in_s->p));
411 return 1;
412 }
413 out_uint8a(g_in_s, data, bytes);
414 if (g_in_s->p == g_in_s->end)
415 {
416 g_in_s->p = g_in_s->data;
417 rv = audin_process_msg(chan_id, g_in_s);
418 free_stream(g_in_s);
419 g_in_s = NULL;
420 return rv;
421 }
422 return 0;
423 }
424
425 /*****************************************************************************/
426 static int
audin_data_first(int chan_id,char * data,int bytes,int total_bytes)427 audin_data_first(int chan_id, char *data, int bytes, int total_bytes)
428 {
429 LOG_DEVEL(LOG_LEVEL_DEBUG, "audin_data_first:");
430 if (g_in_s != NULL)
431 {
432 LOG_DEVEL(LOG_LEVEL_ERROR, "audin_data_first: warning g_in_s is not nil");
433 free_stream(g_in_s);
434 }
435 make_stream(g_in_s);
436 init_stream(g_in_s, total_bytes);
437 g_in_s->end = g_in_s->data + total_bytes;
438 return audin_data_fragment(chan_id, data, bytes);
439 }
440
441 /*****************************************************************************/
442 static int
audin_data(int chan_id,char * data,int bytes)443 audin_data(int chan_id, char *data, int bytes)
444 {
445 struct stream ls;
446
447 LOG_DEVEL_HEXDUMP(LOG_LEVEL_TRACE, "audin_data:", data, bytes);
448 if (g_in_s == NULL)
449 {
450 g_memset(&ls, 0, sizeof(ls));
451 ls.data = data;
452 ls.p = ls.data;
453 ls.end = ls.p + bytes;
454 return audin_process_msg(chan_id, &ls);
455 }
456 return audin_data_fragment(chan_id, data, bytes);
457 }
458
459 /*****************************************************************************/
460 int
audin_init(void)461 audin_init(void)
462 {
463 LOG_DEVEL(LOG_LEVEL_INFO, "audin_init:");
464 g_memset(&g_audin_info, 0, sizeof(g_audin_info));
465 g_audin_info.open_response = audin_open_response;
466 g_audin_info.close_response = audin_close_response;
467 g_audin_info.data_first = audin_data_first;
468 g_audin_info.data = audin_data;
469 g_audin_chanid = 0;
470 g_in_s = NULL;
471 return 0;
472 }
473
474 /*****************************************************************************/
475 int
audin_deinit(void)476 audin_deinit(void)
477 {
478 LOG_DEVEL(LOG_LEVEL_INFO, "audin_deinit:");
479 return 0;
480 }
481
482 /*****************************************************************************/
483 int
audin_start(void)484 audin_start(void)
485 {
486 int error;
487 struct stream *s;
488
489 LOG_DEVEL(LOG_LEVEL_INFO, "audin_start:");
490 if (g_audin_chanid != 0)
491 {
492 return 1;
493 }
494
495 /* if there is any data in FIFO, discard it */
496 while ((s = (struct stream *) fifo_remove(&g_in_fifo)) != NULL)
497 {
498 xstream_free(s);
499 }
500 g_bytes_in_fifo = 0;
501
502 error = chansrv_drdynvc_open(AUDIN_NAME, AUDIN_FLAGS,
503 &g_audin_info, /* callback functions */
504 &g_audin_chanid); /* chansrv chan_id */
505 LOG_DEVEL(LOG_LEVEL_ERROR, "audin_start: error %d g_audin_chanid %d", error, g_audin_chanid);
506 return error;
507 }
508
509 /*****************************************************************************/
510 int
audin_stop(void)511 audin_stop(void)
512 {
513 LOG_DEVEL(LOG_LEVEL_INFO, "audin_stop:");
514 chansrv_drdynvc_close(g_audin_chanid);
515 return 0;
516 }
517