Renamed plugins from 'opensl_es' to 'opensles'
[platform/upstream/freerdp.git] / channels / rdpsnd / client / rdpsnd_main.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * Audio Output Virtual Channel
4  *
5  * Copyright 2009-2011 Jay Sorg
6  * Copyright 2010-2011 Vic Lee
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #ifndef _WIN32
26 #include <sys/time.h>
27 #include <signal.h>
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include <winpr/crt.h>
35 #include <winpr/synch.h>
36 #include <winpr/print.h>
37 #include <winpr/cmdline.h>
38 #include <winpr/sysinfo.h>
39 #include <winpr/collections.h>
40
41 #include <freerdp/types.h>
42 #include <freerdp/addin.h>
43 #include <freerdp/constants.h>
44 #include <winpr/stream.h>
45 #include <freerdp/utils/signal.h>
46 #include <freerdp/utils/svc_plugin.h>
47
48 #include "rdpsnd_main.h"
49
50 #define TIME_DELAY_MS   65
51
52 struct rdpsnd_plugin
53 {
54         rdpSvcPlugin plugin;
55
56         HANDLE thread;
57         wMessageQueue* queue;
58
59         BYTE cBlockNo;
60         int wCurrentFormatNo;
61
62         AUDIO_FORMAT* ServerFormats;
63         UINT16 NumberOfServerFormats;
64
65         AUDIO_FORMAT* ClientFormats;
66         UINT16 NumberOfClientFormats;
67
68         BOOL expectingWave;
69         BYTE waveData[4];
70         UINT16 waveDataSize;
71         UINT32 wTimeStamp;
72
73         int latency;
74         BOOL isOpen;
75         UINT16 fixedFormat;
76         UINT16 fixedChannel;
77         UINT32 fixedRate;
78
79         char* subsystem;
80         char* device_name;
81
82         /* Device plugin */
83         rdpsndDevicePlugin* device;
84 };
85
86 void rdpsnd_send_wave_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, BYTE cConfirmedBlockNo);
87
88 static void* rdpsnd_schedule_thread(void* arg)
89 {
90         wMessage message;
91         UINT16 wTimeDiff;
92         UINT16 wTimeStamp;
93         UINT16 wCurrentTime;
94         RDPSND_WAVE* wave;
95         rdpsndPlugin* rdpsnd = (rdpsndPlugin*) arg;
96
97         while (1)
98         {
99                 if (!MessageQueue_Wait(rdpsnd->queue))
100                         break;
101
102                 if (!MessageQueue_Peek(rdpsnd->queue, &message, TRUE))
103                         break;
104
105                 if (message.id == WMQ_QUIT)
106                         break;
107
108                 wave = (RDPSND_WAVE*) message.wParam;
109                 wCurrentTime = (UINT16) GetTickCount();
110                 wTimeStamp = wave->wLocalTimeB;
111
112                 if (wCurrentTime <= wTimeStamp)
113                 {
114                         wTimeDiff = wTimeStamp - wCurrentTime;
115                         Sleep(wTimeDiff);
116                 }
117
118                 rdpsnd_send_wave_confirm_pdu(rdpsnd, wave->wTimeStampB, wave->cBlockNo);
119                 free(wave);
120         }
121
122         return NULL;
123 }
124
125 void rdpsnd_send_quality_mode_pdu(rdpsndPlugin* rdpsnd)
126 {
127         wStream* pdu;
128
129         pdu = Stream_New(NULL, 8);
130         Stream_Write_UINT8(pdu, SNDC_QUALITYMODE); /* msgType */
131         Stream_Write_UINT8(pdu, 0); /* bPad */
132         Stream_Write_UINT16(pdu, 4); /* BodySize */
133         Stream_Write_UINT16(pdu, HIGH_QUALITY); /* wQualityMode */
134         Stream_Write_UINT16(pdu, 0); /* Reserved */
135
136         svc_plugin_send((rdpSvcPlugin*) rdpsnd, pdu);
137 }
138
139 void rdpsnd_select_supported_audio_formats(rdpsndPlugin* rdpsnd)
140 {
141         int index;
142         AUDIO_FORMAT* serverFormat;
143         AUDIO_FORMAT* clientFormat;
144
145         rdpsnd_free_audio_formats(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats);
146         rdpsnd->NumberOfClientFormats = 0;
147         rdpsnd->ClientFormats = NULL;
148
149         if (!rdpsnd->NumberOfServerFormats)
150                 return;
151
152         rdpsnd->ClientFormats = (AUDIO_FORMAT*) malloc(sizeof(AUDIO_FORMAT) * rdpsnd->NumberOfServerFormats);
153         for (index = 0; index < (int) rdpsnd->NumberOfServerFormats; index++)
154         {
155                 serverFormat = &rdpsnd->ServerFormats[index];
156
157                 if (rdpsnd->fixedFormat > 0 && (rdpsnd->fixedFormat != serverFormat->wFormatTag))
158                         continue;
159
160                 if (rdpsnd->fixedChannel > 0 && (rdpsnd->fixedChannel != serverFormat->nChannels))
161                         continue;
162
163                 if (rdpsnd->fixedRate > 0 && (rdpsnd->fixedRate != serverFormat->nSamplesPerSec))
164                         continue;
165
166                 if (rdpsnd->device && rdpsnd->device->FormatSupported(rdpsnd->device, serverFormat))
167                 {
168                         clientFormat = &rdpsnd->ClientFormats[rdpsnd->NumberOfClientFormats++];
169
170                         CopyMemory(clientFormat, serverFormat, sizeof(AUDIO_FORMAT));
171                         clientFormat->cbSize = 0;
172
173                         if (serverFormat->cbSize > 0)
174                         {
175                                 clientFormat->data = (BYTE*) malloc(serverFormat->cbSize);
176                                 CopyMemory(clientFormat->data, serverFormat->data, serverFormat->cbSize);
177                                 clientFormat->cbSize = serverFormat->cbSize;
178                         }
179                 }
180         }
181
182 #if 0
183         fprintf(stderr, "Server ");
184         rdpsnd_print_audio_formats(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats);
185         fprintf(stderr, "\n");
186
187         fprintf(stderr, "Client ");
188         rdpsnd_print_audio_formats(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats);
189         fprintf(stderr, "\n");
190 #endif
191 }
192
193 void rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd)
194 {
195         int index;
196         wStream* pdu;
197         UINT16 length;
198         UINT32 dwVolume;
199         UINT16 dwVolumeLeft;
200         UINT16 dwVolumeRight;
201         UINT16 wNumberOfFormats;
202         AUDIO_FORMAT* clientFormat;
203
204         dwVolumeLeft = ((50 * 0xFFFF) / 100); /* 50% */
205         dwVolumeRight = ((50 * 0xFFFF) / 100); /* 50% */
206         dwVolume = (dwVolumeLeft << 16) | dwVolumeRight;
207
208         if (rdpsnd->device)
209         {
210                 if (rdpsnd->device->GetVolume)
211                         dwVolume = rdpsnd->device->GetVolume(rdpsnd->device);
212         }
213
214         wNumberOfFormats = rdpsnd->NumberOfClientFormats;
215
216         length = 4 + 20;
217
218         for (index = 0; index < (int) wNumberOfFormats; index++)
219                 length += (18 + rdpsnd->ClientFormats[index].cbSize);
220
221         pdu = Stream_New(NULL, length);
222
223         Stream_Write_UINT8(pdu, SNDC_FORMATS); /* msgType */
224         Stream_Write_UINT8(pdu, 0); /* bPad */
225         Stream_Write_UINT16(pdu, length - 4); /* BodySize */
226
227         Stream_Write_UINT32(pdu, TSSNDCAPS_ALIVE | TSSNDCAPS_VOLUME); /* dwFlags */
228         Stream_Write_UINT32(pdu, dwVolume); /* dwVolume */
229         Stream_Write_UINT32(pdu, 0); /* dwPitch */
230         Stream_Write_UINT16(pdu, 0); /* wDGramPort */
231         Stream_Write_UINT16(pdu, wNumberOfFormats); /* wNumberOfFormats */
232         Stream_Write_UINT8(pdu, 0); /* cLastBlockConfirmed */
233         Stream_Write_UINT16(pdu, 6); /* wVersion */
234         Stream_Write_UINT8(pdu, 0); /* bPad */
235
236         for (index = 0; index < (int) wNumberOfFormats; index++)
237         {
238                 clientFormat = &rdpsnd->ClientFormats[index];
239
240                 Stream_Write_UINT16(pdu, clientFormat->wFormatTag);
241                 Stream_Write_UINT16(pdu, clientFormat->nChannels);
242                 Stream_Write_UINT32(pdu, clientFormat->nSamplesPerSec);
243                 Stream_Write_UINT32(pdu, clientFormat->nAvgBytesPerSec);
244                 Stream_Write_UINT16(pdu, clientFormat->nBlockAlign);
245                 Stream_Write_UINT16(pdu, clientFormat->wBitsPerSample);
246                 Stream_Write_UINT16(pdu, clientFormat->cbSize);
247
248                 if (clientFormat->cbSize > 0)
249                         Stream_Write(pdu, clientFormat->data, clientFormat->cbSize);
250         }
251
252         svc_plugin_send((rdpSvcPlugin*) rdpsnd, pdu);
253 }
254
255 void rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream* s)
256 {
257         int index;
258         UINT16 wVersion;
259         AUDIO_FORMAT* format;
260         UINT16 wNumberOfFormats;
261
262         rdpsnd_free_audio_formats(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats);
263         rdpsnd->NumberOfServerFormats = 0;
264         rdpsnd->ServerFormats = NULL;
265
266         Stream_Seek_UINT32(s); /* dwFlags */
267         Stream_Seek_UINT32(s); /* dwVolume */
268         Stream_Seek_UINT32(s); /* dwPitch */
269         Stream_Seek_UINT16(s); /* wDGramPort */
270         Stream_Read_UINT16(s, wNumberOfFormats);
271         Stream_Read_UINT8(s, rdpsnd->cBlockNo); /* cLastBlockConfirmed */
272         Stream_Read_UINT16(s, wVersion); /* wVersion */
273         Stream_Seek_UINT8(s); /* bPad */
274
275         rdpsnd->NumberOfServerFormats = wNumberOfFormats;
276         rdpsnd->ServerFormats = (AUDIO_FORMAT*) malloc(sizeof(AUDIO_FORMAT) * wNumberOfFormats);
277
278         for (index = 0; index < (int) wNumberOfFormats; index++)
279         {
280                 format = &rdpsnd->ServerFormats[index];
281
282                 Stream_Read_UINT16(s, format->wFormatTag); /* wFormatTag */
283                 Stream_Read_UINT16(s, format->nChannels); /* nChannels */
284                 Stream_Read_UINT32(s, format->nSamplesPerSec); /* nSamplesPerSec */
285                 Stream_Read_UINT32(s, format->nAvgBytesPerSec); /* nAvgBytesPerSec */
286                 Stream_Read_UINT16(s, format->nBlockAlign); /* nBlockAlign */
287                 Stream_Read_UINT16(s, format->wBitsPerSample); /* wBitsPerSample */
288                 Stream_Read_UINT16(s, format->cbSize); /* cbSize */
289
290                 format->data = (BYTE*) malloc(format->cbSize);
291                 Stream_Read(s, format->data, format->cbSize);
292         }
293
294         rdpsnd_select_supported_audio_formats(rdpsnd);
295
296         rdpsnd_send_client_audio_formats(rdpsnd);
297
298         if (wVersion >= 6)
299                 rdpsnd_send_quality_mode_pdu(rdpsnd);
300 }
301
302 void rdpsnd_send_training_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, UINT16 wPackSize)
303 {
304         wStream* pdu;
305
306         pdu = Stream_New(NULL, 8);
307         Stream_Write_UINT8(pdu, SNDC_TRAINING); /* msgType */
308         Stream_Write_UINT8(pdu, 0); /* bPad */
309         Stream_Write_UINT16(pdu, 4); /* BodySize */
310         Stream_Write_UINT16(pdu, wTimeStamp);
311         Stream_Write_UINT16(pdu, wPackSize);
312
313         svc_plugin_send((rdpSvcPlugin*) rdpsnd, pdu);
314 }
315
316 static void rdpsnd_recv_training_pdu(rdpsndPlugin* rdpsnd, wStream* s)
317 {
318         UINT16 wTimeStamp;
319         UINT16 wPackSize;
320
321         Stream_Read_UINT16(s, wTimeStamp);
322         Stream_Read_UINT16(s, wPackSize);
323
324         rdpsnd_send_training_confirm_pdu(rdpsnd, wTimeStamp, wPackSize);
325 }
326
327 static void rdpsnd_recv_wave_info_pdu(rdpsndPlugin* rdpsnd, wStream* s, UINT16 BodySize)
328 {
329         UINT16 wFormatNo;
330         AUDIO_FORMAT* format;
331
332         rdpsnd->expectingWave = TRUE;
333
334         Stream_Read_UINT16(s, rdpsnd->wTimeStamp);
335         Stream_Read_UINT16(s, wFormatNo);
336         Stream_Read_UINT8(s, rdpsnd->cBlockNo);
337         Stream_Seek(s, 3); /* bPad */
338         Stream_Read(s, rdpsnd->waveData, 4);
339
340         rdpsnd->waveDataSize = BodySize - 8;
341
342         format = &rdpsnd->ClientFormats[wFormatNo];
343
344         if (!rdpsnd->isOpen)
345         {
346                 rdpsnd->isOpen = TRUE;
347                 rdpsnd->wCurrentFormatNo = wFormatNo;
348
349                 //rdpsnd_print_audio_format(format);
350
351                 if (rdpsnd->device)
352                 {
353                         IFCALL(rdpsnd->device->Open, rdpsnd->device, format, rdpsnd->latency);
354                 }
355         }
356         else if (wFormatNo != rdpsnd->wCurrentFormatNo)
357         {
358                 rdpsnd->wCurrentFormatNo = wFormatNo;
359
360                 if (rdpsnd->device)
361                 {
362                         IFCALL(rdpsnd->device->SetFormat, rdpsnd->device, format, rdpsnd->latency);
363                 }
364         }
365 }
366
367 void rdpsnd_send_wave_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, BYTE cConfirmedBlockNo)
368 {
369         wStream* pdu;
370
371         pdu = Stream_New(NULL, 8);
372         Stream_Write_UINT8(pdu, SNDC_WAVECONFIRM);
373         Stream_Write_UINT8(pdu, 0);
374         Stream_Write_UINT16(pdu, 4);
375         Stream_Write_UINT16(pdu, wTimeStamp);
376         Stream_Write_UINT8(pdu, cConfirmedBlockNo); /* cConfirmedBlockNo */
377         Stream_Write_UINT8(pdu, 0); /* bPad */
378
379         svc_plugin_send((rdpSvcPlugin*) rdpsnd, pdu);
380 }
381
382 void rdpsnd_device_send_wave_confirm_pdu(rdpsndDevicePlugin* device, RDPSND_WAVE* wave)
383 {
384         MessageQueue_Post(device->rdpsnd->queue, NULL, 0, (void*) wave, NULL);
385 }
386
387 static void rdpsnd_recv_wave_pdu(rdpsndPlugin* rdpsnd, wStream* s)
388 {
389         int size;
390         BYTE* data;
391         RDPSND_WAVE* wave;
392         AUDIO_FORMAT* format;
393
394         rdpsnd->expectingWave = FALSE;
395
396         /**
397          * The Wave PDU is a special case: it is always sent after a Wave Info PDU,
398          * and we do not process its header. Instead, the header is pad that needs
399          * to be filled with the first four bytes of the audio sample data sent as
400          * part of the preceding Wave Info PDU.
401          */
402
403         CopyMemory(Stream_Buffer(s), rdpsnd->waveData, 4);
404
405         data = Stream_Buffer(s);
406         size = Stream_Capacity(s);
407
408         wave = (RDPSND_WAVE*) malloc(sizeof(RDPSND_WAVE));
409
410         wave->wLocalTimeA = GetTickCount();
411         wave->wTimeStampA = rdpsnd->wTimeStamp;
412         wave->wFormatNo = rdpsnd->wCurrentFormatNo;
413         wave->cBlockNo = rdpsnd->cBlockNo;
414
415         wave->data = data;
416         wave->length = size;
417
418         format = &rdpsnd->ClientFormats[rdpsnd->wCurrentFormatNo];
419         wave->wAudioLength = rdpsnd_compute_audio_time_length(format, size);
420
421         if (!rdpsnd->device)
422         {
423                 free(wave);
424                 return;
425         }
426
427         if (rdpsnd->device->WaveDecode)
428         {
429                 IFCALL(rdpsnd->device->WaveDecode, rdpsnd->device, wave);
430         }
431
432         if (rdpsnd->device->WavePlay)
433         {
434                 IFCALL(rdpsnd->device->WavePlay, rdpsnd->device, wave);
435         }
436         else
437         {
438                 IFCALL(rdpsnd->device->Play, rdpsnd->device, data, size);
439         }
440
441         if (!rdpsnd->device->WavePlay)
442         {
443                 wave->wTimeStampB = rdpsnd->wTimeStamp + wave->wAudioLength + TIME_DELAY_MS;
444                 wave->wLocalTimeB = wave->wLocalTimeA + wave->wAudioLength + TIME_DELAY_MS;
445                 rdpsnd->device->WaveConfirm(rdpsnd->device, wave);
446         }
447 }
448
449 static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd)
450 {
451         DEBUG_SVC("server closes.");
452
453         if (rdpsnd->device)
454         {
455                 IFCALL(rdpsnd->device->Close, rdpsnd->device);
456         }
457
458         rdpsnd->isOpen = FALSE;
459 }
460
461 static void rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s)
462 {
463         UINT32 dwVolume;
464
465         Stream_Read_UINT32(s, dwVolume);
466         DEBUG_SVC("dwVolume 0x%X", dwVolume);
467
468         if (rdpsnd->device)
469         {
470                 IFCALL(rdpsnd->device->SetVolume, rdpsnd->device, dwVolume);
471         }
472 }
473
474 static void rdpsnd_recv_pdu(rdpSvcPlugin* plugin, wStream* s)
475 {
476         BYTE msgType;
477         UINT16 BodySize;
478         rdpsndPlugin* rdpsnd = (rdpsndPlugin*) plugin;
479
480         if (rdpsnd->expectingWave)
481         {
482                 rdpsnd_recv_wave_pdu(rdpsnd, s);
483                 Stream_Free(s, TRUE);
484                 return;
485         }
486
487         Stream_Read_UINT8(s, msgType); /* msgType */
488         Stream_Seek_UINT8(s); /* bPad */
489         Stream_Read_UINT16(s, BodySize);
490
491         //fprintf(stderr, "msgType %d BodySize %d\n", msgType, BodySize);
492
493         switch (msgType)
494         {
495                 case SNDC_FORMATS:
496                         rdpsnd_recv_server_audio_formats_pdu(rdpsnd, s);
497                         break;
498
499                 case SNDC_TRAINING:
500                         rdpsnd_recv_training_pdu(rdpsnd, s);
501                         break;
502
503                 case SNDC_WAVE:
504                         rdpsnd_recv_wave_info_pdu(rdpsnd, s, BodySize);
505                         break;
506
507                 case SNDC_CLOSE:
508                         rdpsnd_recv_close_pdu(rdpsnd);
509                         break;
510
511                 case SNDC_SETVOLUME:
512                         rdpsnd_recv_volume_pdu(rdpsnd, s);
513                         break;
514
515                 default:
516                         DEBUG_WARN("unknown msgType %d", msgType);
517                         break;
518         }
519
520         Stream_Free(s, TRUE);
521 }
522
523 static void rdpsnd_register_device_plugin(rdpsndPlugin* rdpsnd, rdpsndDevicePlugin* device)
524 {
525         if (rdpsnd->device)
526         {
527                 DEBUG_WARN("existing device, abort.");
528                 return;
529         }
530
531         rdpsnd->device = device;
532         device->rdpsnd = rdpsnd;
533
534         device->WaveConfirm = rdpsnd_device_send_wave_confirm_pdu;
535 }
536
537 static BOOL rdpsnd_load_device_plugin(rdpsndPlugin* rdpsnd, const char* name, ADDIN_ARGV* args)
538 {
539         PFREERDP_RDPSND_DEVICE_ENTRY entry;
540         FREERDP_RDPSND_DEVICE_ENTRY_POINTS entryPoints;
541
542         entry = (PFREERDP_RDPSND_DEVICE_ENTRY) freerdp_load_channel_addin_entry("rdpsnd", (LPSTR) name, NULL, 0);
543
544         if (!entry)
545                 return FALSE;
546
547         entryPoints.rdpsnd = rdpsnd;
548         entryPoints.pRegisterRdpsndDevice = rdpsnd_register_device_plugin;
549         entryPoints.args = args;
550
551         if (entry(&entryPoints) != 0)
552         {
553                 DEBUG_WARN("%s entry returns error.", name);
554                 return FALSE;
555         }
556
557         return TRUE;
558 }
559
560 void rdpsnd_set_subsystem(rdpsndPlugin* rdpsnd, char* subsystem)
561 {
562         if (rdpsnd->subsystem)
563                 free(rdpsnd->subsystem);
564
565         rdpsnd->subsystem = _strdup(subsystem);
566 }
567
568 void rdpsnd_set_device_name(rdpsndPlugin* rdpsnd, char* device_name)
569 {
570         if (rdpsnd->device_name)
571                 free(rdpsnd->device_name);
572
573         rdpsnd->device_name = _strdup(device_name);
574 }
575
576 COMMAND_LINE_ARGUMENT_A rdpsnd_args[] =
577 {
578         { "sys", COMMAND_LINE_VALUE_REQUIRED, "<subsystem>", NULL, NULL, -1, NULL, "subsystem" },
579         { "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL, NULL, -1, NULL, "device" },
580         { "format", COMMAND_LINE_VALUE_REQUIRED, "<format>", NULL, NULL, -1, NULL, "format" },
581         { "rate", COMMAND_LINE_VALUE_REQUIRED, "<rate>", NULL, NULL, -1, NULL, "rate" },
582         { "channel", COMMAND_LINE_VALUE_REQUIRED, "<channel>", NULL, NULL, -1, NULL, "channel" },
583         { "latency", COMMAND_LINE_VALUE_REQUIRED, "<latency>", NULL, NULL, -1, NULL, "latency" },
584         { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
585 };
586
587 static void rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args)
588 {
589         int status;
590         DWORD flags;
591         COMMAND_LINE_ARGUMENT_A* arg;
592
593         flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON;
594
595         status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv,
596                         rdpsnd_args, flags, rdpsnd, NULL, NULL);
597
598         arg = rdpsnd_args;
599
600         do
601         {
602                 if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
603                         continue;
604
605                 CommandLineSwitchStart(arg)
606
607                 CommandLineSwitchCase(arg, "sys")
608                 {
609                         rdpsnd_set_subsystem(rdpsnd, arg->Value);
610                 }
611                 CommandLineSwitchCase(arg, "dev")
612                 {
613                         rdpsnd_set_device_name(rdpsnd, arg->Value);
614                 }
615                 CommandLineSwitchCase(arg, "format")
616                 {
617                         rdpsnd->fixedFormat = atoi(arg->Value);
618                 }
619                 CommandLineSwitchCase(arg, "rate")
620                 {
621                         rdpsnd->fixedRate = atoi(arg->Value);
622                 }
623                 CommandLineSwitchCase(arg, "channel")
624                 {
625                         rdpsnd->fixedChannel = atoi(arg->Value);
626                 }
627                 CommandLineSwitchCase(arg, "latency")
628                 {
629                         rdpsnd->latency = atoi(arg->Value);
630                 }
631                 CommandLineSwitchDefault(arg)
632                 {
633
634                 }
635
636                 CommandLineSwitchEnd(arg)
637         }
638         while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
639 }
640
641 static void rdpsnd_process_connect(rdpSvcPlugin* plugin)
642 {
643         ADDIN_ARGV* args;
644         rdpsndPlugin* rdpsnd = (rdpsndPlugin*) plugin;
645
646         DEBUG_SVC("connecting");
647
648         rdpsnd->latency = -1;
649         rdpsnd->queue = MessageQueue_New();
650         rdpsnd->thread = CreateThread(NULL, 0,
651                         (LPTHREAD_START_ROUTINE) rdpsnd_schedule_thread,
652                         (void*) plugin, 0, NULL);
653
654         args = (ADDIN_ARGV*) plugin->channel_entry_points.pExtendedData;
655
656         if (args)
657                 rdpsnd_process_addin_args(rdpsnd, args);
658
659         if (rdpsnd->subsystem)
660         {
661                 if (strcmp(rdpsnd->subsystem, "fake") == 0)
662                         return;
663
664                 rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args);
665         }
666
667 #if defined(WITH_IOSAUDIO)
668         if (!rdpsnd->device)
669         {
670                 rdpsnd_set_subsystem(rdpsnd, "ios");
671                 rdpsnd_set_device_name(rdpsnd, "");
672                 rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args);
673         }
674 #endif
675
676 #if defined(WITH_OPENSLES)
677         if (!rdpsnd->device)
678         {
679                 rdpsnd_set_subsystem(rdpsnd, "opensles");
680                 rdpsnd_set_device_name(rdpsnd, "");
681                 rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args);
682         }
683 #endif
684
685 #if defined(WITH_PULSE)
686         if (!rdpsnd->device)
687         {
688                 rdpsnd_set_subsystem(rdpsnd, "pulse");
689                 rdpsnd_set_device_name(rdpsnd, "");
690                 rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args);
691         }
692 #endif
693
694 #if defined(WITH_ALSA)
695         if (!rdpsnd->device)
696         {
697                 rdpsnd_set_subsystem(rdpsnd, "alsa");
698                 rdpsnd_set_device_name(rdpsnd, "default");
699                 rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args);
700         }
701 #endif
702
703 #if defined(WITH_MACAUDIO)
704         if (!rdpsnd->device)
705         {
706                 rdpsnd_set_subsystem(rdpsnd, "macaudio");
707                 rdpsnd_set_device_name(rdpsnd, "default");
708                 rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args);
709         }
710 #endif
711
712 #if defined(WITH_WINMM)
713         if (!rdpsnd->device)
714         {
715                 rdpsnd_set_subsystem(rdpsnd, "winmm");
716                 rdpsnd_set_device_name(rdpsnd, "");
717                 rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args);
718         }
719 #endif
720
721         if (!rdpsnd->device)
722         {
723                 DEBUG_WARN("no sound device.");
724                 return;
725         }
726 }
727
728 static void rdpsnd_process_event(rdpSvcPlugin* plugin, wMessage* event)
729 {
730         freerdp_event_free(event);
731 }
732
733 static void rdpsnd_process_terminate(rdpSvcPlugin* plugin)
734 {
735         rdpsndPlugin* rdpsnd = (rdpsndPlugin*) plugin;
736
737         if (rdpsnd->device)
738                 IFCALL(rdpsnd->device->Free, rdpsnd->device);
739
740         MessageQueue_PostQuit(rdpsnd->queue, 0);
741         WaitForSingleObject(rdpsnd->thread, INFINITE);
742
743         MessageQueue_Free(rdpsnd->queue);
744         CloseHandle(rdpsnd->thread);
745
746         if (rdpsnd->subsystem)
747                 free(rdpsnd->subsystem);
748
749         if (rdpsnd->device_name)
750                 free(rdpsnd->device_name);
751
752         rdpsnd_free_audio_formats(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats);
753         rdpsnd->NumberOfServerFormats = 0;
754         rdpsnd->ServerFormats = NULL;
755
756         rdpsnd_free_audio_formats(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats);
757         rdpsnd->NumberOfClientFormats = 0;
758         rdpsnd->ClientFormats = NULL;
759 }
760
761 /* rdpsnd is always built-in */
762 #define VirtualChannelEntry     rdpsnd_VirtualChannelEntry
763
764 int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
765 {
766         rdpsndPlugin* _p;
767
768         _p = (rdpsndPlugin*) malloc(sizeof(rdpsndPlugin));
769         ZeroMemory(_p, sizeof(rdpsndPlugin));
770
771         _p->plugin.channel_def.options =
772                         CHANNEL_OPTION_INITIALIZED |
773                         CHANNEL_OPTION_ENCRYPT_RDP;
774
775         strcpy(_p->plugin.channel_def.name, "rdpsnd");
776
777         _p->plugin.connect_callback = rdpsnd_process_connect;
778         _p->plugin.receive_callback = rdpsnd_recv_pdu;
779         _p->plugin.event_callback = rdpsnd_process_event;
780         _p->plugin.terminate_callback = rdpsnd_process_terminate;
781
782 #if !defined(_WIN32) && !defined(ANDROID)
783         {
784                 sigset_t mask;
785                 sigemptyset(&mask);
786                 sigaddset(&mask, SIGIO);
787                 pthread_sigmask(SIG_BLOCK, &mask, NULL);
788         }
789 #endif
790
791         svc_plugin_init((rdpSvcPlugin*) _p, pEntryPoints);
792
793         return 1;
794 }