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