Initial commit - from Precise source
[freerdp-ubuntu-pcb-backport.git] / channels / rdpsnd / rdpsnd_main.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol client.
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 #ifndef _WIN32
22 #include <sys/time.h>
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <freerdp/constants.h>
29 #include <freerdp/types.h>
30 #include <freerdp/utils/memory.h>
31 #include <freerdp/utils/stream.h>
32 #include <freerdp/utils/list.h>
33 #include <freerdp/utils/load_plugin.h>
34 #include <freerdp/utils/svc_plugin.h>
35
36 #include "rdpsnd_main.h"
37
38 #define SNDC_CLOSE         1
39 #define SNDC_WAVE          2
40 #define SNDC_SETVOLUME     3
41 #define SNDC_SETPITCH      4
42 #define SNDC_WAVECONFIRM   5
43 #define SNDC_TRAINING      6
44 #define SNDC_FORMATS       7
45 #define SNDC_CRYPTKEY      8
46 #define SNDC_WAVEENCRYPT   9
47 #define SNDC_UDPWAVE       10
48 #define SNDC_UDPWAVELAST   11
49 #define SNDC_QUALITYMODE   12
50
51 #define TSSNDCAPS_ALIVE  1
52 #define TSSNDCAPS_VOLUME 2
53 #define TSSNDCAPS_PITCH  4
54
55 #define DYNAMIC_QUALITY  0x0000
56 #define MEDIUM_QUALITY   0x0001
57 #define HIGH_QUALITY     0x0002
58
59 struct rdpsnd_plugin
60 {
61         rdpSvcPlugin plugin;
62
63         LIST* data_out_list;
64
65         uint8 cBlockNo;
66         rdpsndFormat* supported_formats;
67         int n_supported_formats;
68         int current_format;
69
70         boolean expectingWave;
71         uint8 waveData[4];
72         uint16 waveDataSize;
73         uint32 wTimeStamp; /* server timestamp */
74         uint32 wave_timestamp; /* client timestamp */
75
76         boolean is_open;
77         uint32 close_timestamp;
78
79         uint16 fixed_format;
80         uint16 fixed_channel;
81         uint32 fixed_rate;
82         int latency;
83
84         /* Device plugin */
85         rdpsndDevicePlugin* device;
86 };
87
88 struct data_out_item
89 {
90         STREAM* data_out;
91         uint32 out_timestamp;
92 };
93
94 /* get time in milliseconds */
95 static uint32 get_mstime(void)
96 {
97         struct timeval tp;
98
99         gettimeofday(&tp, 0);
100         return (tp.tv_sec * 1000) + (tp.tv_usec / 1000);
101 }
102
103 /* process the linked list of data that has queued to be sent */
104 static void rdpsnd_process_interval(rdpSvcPlugin* plugin)
105 {
106         rdpsndPlugin* rdpsnd = (rdpsndPlugin*)plugin;
107         struct data_out_item* item;
108         uint32 cur_time;
109
110         while (rdpsnd->data_out_list->head)
111         {
112                 item = (struct data_out_item*)rdpsnd->data_out_list->head->data;
113                 cur_time = get_mstime();
114                 if (cur_time <= item->out_timestamp)
115                         break;
116
117                 item = (struct data_out_item*)list_dequeue(rdpsnd->data_out_list);
118                 svc_plugin_send(plugin, item->data_out);
119                 xfree(item);
120
121                 DEBUG_SVC("processed data_out");
122         }
123
124         if (rdpsnd->is_open && rdpsnd->close_timestamp > 0)
125         {
126                 cur_time = get_mstime();
127                 if (cur_time > rdpsnd->close_timestamp)
128                 {
129                         if (rdpsnd->device)
130                                 IFCALL(rdpsnd->device->Close, rdpsnd->device);
131                         rdpsnd->is_open = false;
132                         rdpsnd->close_timestamp = 0;
133
134                         DEBUG_SVC("processed close");
135                 }
136         }
137
138         if (rdpsnd->data_out_list->head == NULL && !rdpsnd->is_open)
139         {
140                 rdpsnd->plugin.interval_ms = 0;
141         }
142 }
143
144 static void rdpsnd_free_supported_formats(rdpsndPlugin* rdpsnd)
145 {
146         uint16 i;
147
148         for (i = 0; i < rdpsnd->n_supported_formats; i++)
149                 xfree(rdpsnd->supported_formats[i].data);
150         xfree(rdpsnd->supported_formats);
151
152         rdpsnd->supported_formats = NULL;
153         rdpsnd->n_supported_formats = 0;
154 }
155
156 /* receives a list of server supported formats and returns a list
157    of client supported formats */
158 static void rdpsnd_process_message_formats(rdpsndPlugin* rdpsnd, STREAM* data_in)
159 {
160         uint16 wNumberOfFormats;
161         uint16 nFormat;
162         uint16 wVersion;
163         STREAM* data_out;
164         rdpsndFormat* out_formats;
165         uint16 n_out_formats;
166         rdpsndFormat* format;
167         uint8* format_mark;
168         uint8* data_mark;
169         int pos;
170
171         rdpsnd_free_supported_formats(rdpsnd);
172
173         stream_seek_uint32(data_in); /* dwFlags */
174         stream_seek_uint32(data_in); /* dwVolume */
175         stream_seek_uint32(data_in); /* dwPitch */
176         stream_seek_uint16(data_in); /* wDGramPort */
177         stream_read_uint16(data_in, wNumberOfFormats);
178         stream_read_uint8(data_in, rdpsnd->cBlockNo); /* cLastBlockConfirmed */
179         stream_read_uint16(data_in, wVersion);
180         stream_seek_uint8(data_in); /* bPad */
181
182         DEBUG_SVC("wNumberOfFormats %d wVersion %d", wNumberOfFormats, wVersion);
183         if (wNumberOfFormats < 1)
184         {
185                 DEBUG_WARN("wNumberOfFormats is 0");
186                 return;
187         }
188
189         out_formats = (rdpsndFormat*)xzalloc(wNumberOfFormats * sizeof(rdpsndFormat));
190         n_out_formats = 0;
191
192         data_out = stream_new(24);
193         stream_write_uint8(data_out, SNDC_FORMATS); /* msgType */
194         stream_write_uint8(data_out, 0); /* bPad */
195         stream_seek_uint16(data_out); /* BodySize */
196         stream_write_uint32(data_out, TSSNDCAPS_ALIVE); /* dwFlags */
197         stream_write_uint32(data_out, 0); /* dwVolume */
198         stream_write_uint32(data_out, 0); /* dwPitch */
199         stream_write_uint16_be(data_out, 0); /* wDGramPort */
200         stream_seek_uint16(data_out); /* wNumberOfFormats */
201         stream_write_uint8(data_out, 0); /* cLastBlockConfirmed */
202         stream_write_uint16(data_out, 6); /* wVersion */
203         stream_write_uint8(data_out, 0); /* bPad */
204
205         for (nFormat = 0; nFormat < wNumberOfFormats; nFormat++)
206         {
207                 stream_get_mark(data_in, format_mark);
208                 format = &out_formats[n_out_formats];
209                 stream_read_uint16(data_in, format->wFormatTag);
210                 stream_read_uint16(data_in, format->nChannels);
211                 stream_read_uint32(data_in, format->nSamplesPerSec);
212                 stream_seek_uint32(data_in); /* nAvgBytesPerSec */
213                 stream_read_uint16(data_in, format->nBlockAlign);
214                 stream_read_uint16(data_in, format->wBitsPerSample);
215                 stream_read_uint16(data_in, format->cbSize);
216                 stream_get_mark(data_in, data_mark);
217                 stream_seek(data_in, format->cbSize);
218                 format->data = NULL;
219
220                 DEBUG_SVC("wFormatTag=%d nChannels=%d nSamplesPerSec=%d nBlockAlign=%d wBitsPerSample=%d",
221                         format->wFormatTag, format->nChannels, format->nSamplesPerSec,
222                         format->nBlockAlign, format->wBitsPerSample);
223
224                 if (rdpsnd->fixed_format > 0 && rdpsnd->fixed_format != format->wFormatTag)
225                         continue;
226                 if (rdpsnd->fixed_channel > 0 && rdpsnd->fixed_channel != format->nChannels)
227                         continue;
228                 if (rdpsnd->fixed_rate > 0 && rdpsnd->fixed_rate != format->nSamplesPerSec)
229                         continue;
230                 if (rdpsnd->device && rdpsnd->device->FormatSupported(rdpsnd->device, format))
231                 {
232                         DEBUG_SVC("format supported.");
233
234                         stream_check_size(data_out, 18 + format->cbSize);
235                         stream_write(data_out, format_mark, 18 + format->cbSize);
236                         if (format->cbSize > 0)
237                         {
238                                 format->data = xmalloc(format->cbSize);
239                                 memcpy(format->data, data_mark, format->cbSize);
240                         }
241                         n_out_formats++;
242                 }
243         }
244
245         rdpsnd->n_supported_formats = n_out_formats;
246         if (n_out_formats > 0)
247         {
248                 rdpsnd->supported_formats = out_formats;
249         }
250         else
251         {
252                 xfree(out_formats);
253                 DEBUG_WARN("no formats supported");
254         }
255
256         pos = stream_get_pos(data_out);
257         stream_set_pos(data_out, 2);
258         stream_write_uint16(data_out, pos - 4);
259         stream_set_pos(data_out, 18);
260         stream_write_uint16(data_out, n_out_formats);
261         stream_set_pos(data_out, pos);
262
263         svc_plugin_send((rdpSvcPlugin*)rdpsnd, data_out);
264
265         if (wVersion >= 6)
266         {
267                 data_out = stream_new(8);
268                 stream_write_uint8(data_out, SNDC_QUALITYMODE); /* msgType */
269                 stream_write_uint8(data_out, 0); /* bPad */
270                 stream_write_uint16(data_out, 4); /* BodySize */
271                 stream_write_uint16(data_out, HIGH_QUALITY); /* wQualityMode */
272                 stream_write_uint16(data_out, 0); /* Reserved */
273
274                 svc_plugin_send((rdpSvcPlugin*)rdpsnd, data_out);
275         }
276 }
277
278 /* server is getting a feel of the round trip time */
279 static void rdpsnd_process_message_training(rdpsndPlugin* rdpsnd, STREAM* data_in)
280 {
281         uint16 wTimeStamp;
282         uint16 wPackSize;
283         STREAM* data_out;
284
285         stream_read_uint16(data_in, wTimeStamp);
286         stream_read_uint16(data_in, wPackSize);
287
288         data_out = stream_new(8);
289         stream_write_uint8(data_out, SNDC_TRAINING); /* msgType */
290         stream_write_uint8(data_out, 0); /* bPad */
291         stream_write_uint16(data_out, 4); /* BodySize */
292         stream_write_uint16(data_out, wTimeStamp);
293         stream_write_uint16(data_out, wPackSize);
294
295         svc_plugin_send((rdpSvcPlugin*)rdpsnd, data_out);
296 }
297
298 static void rdpsnd_process_message_wave_info(rdpsndPlugin* rdpsnd, STREAM* data_in, uint16 BodySize)
299 {
300         uint16 wFormatNo;
301
302         stream_read_uint16(data_in, rdpsnd->wTimeStamp);
303         stream_read_uint16(data_in, wFormatNo);
304         stream_read_uint8(data_in, rdpsnd->cBlockNo);
305         stream_seek(data_in, 3); /* bPad */
306         stream_read(data_in, rdpsnd->waveData, 4);
307         rdpsnd->waveDataSize = BodySize - 8;
308         rdpsnd->wave_timestamp = get_mstime();
309         rdpsnd->expectingWave = true;
310
311         DEBUG_SVC("waveDataSize %d wFormatNo %d", rdpsnd->waveDataSize, wFormatNo);
312
313         rdpsnd->close_timestamp = 0;
314         if (!rdpsnd->is_open)
315         {
316                 rdpsnd->current_format = wFormatNo;
317                 rdpsnd->is_open = true;
318                 if (rdpsnd->device)
319                         IFCALL(rdpsnd->device->Open, rdpsnd->device, &rdpsnd->supported_formats[wFormatNo],
320                                 rdpsnd->latency);
321         }
322         else if (wFormatNo != rdpsnd->current_format)
323         {
324                 rdpsnd->current_format = wFormatNo;
325                 if (rdpsnd->device)
326                         IFCALL(rdpsnd->device->SetFormat, rdpsnd->device, &rdpsnd->supported_formats[wFormatNo],
327                                 rdpsnd->latency);
328         }
329 }
330
331 /* header is not removed from data in this function */
332 static void rdpsnd_process_message_wave(rdpsndPlugin* rdpsnd, STREAM* data_in)
333 {
334         uint16 wTimeStamp;
335         uint32 delay_ms;
336         uint32 process_ms;
337         struct data_out_item* item;
338
339         rdpsnd->expectingWave = 0;
340         memcpy(stream_get_head(data_in), rdpsnd->waveData, 4);
341         if (stream_get_size(data_in) != rdpsnd->waveDataSize)
342         {
343                 DEBUG_WARN("size error");
344                 return;
345         }
346         if (rdpsnd->device)
347                 IFCALL(rdpsnd->device->Play, rdpsnd->device, stream_get_head(data_in), stream_get_size(data_in));
348
349         process_ms = get_mstime() - rdpsnd->wave_timestamp;
350         delay_ms = 250;
351         wTimeStamp = rdpsnd->wTimeStamp + delay_ms;
352
353         DEBUG_SVC("data_size %d delay_ms %u process_ms %u",
354                 stream_get_size(data_in), delay_ms, process_ms);
355
356         item = xnew(struct data_out_item);
357         item->data_out = stream_new(8);
358         stream_write_uint8(item->data_out, SNDC_WAVECONFIRM);
359         stream_write_uint8(item->data_out, 0);
360         stream_write_uint16(item->data_out, 4);
361         stream_write_uint16(item->data_out, wTimeStamp);
362         stream_write_uint8(item->data_out, rdpsnd->cBlockNo); /* cConfirmedBlockNo */
363         stream_write_uint8(item->data_out, 0); /* bPad */
364         item->out_timestamp = rdpsnd->wave_timestamp + delay_ms;
365
366         list_enqueue(rdpsnd->data_out_list, item);
367         rdpsnd->plugin.interval_ms = 10;
368 }
369
370 static void rdpsnd_process_message_close(rdpsndPlugin* rdpsnd)
371 {
372         DEBUG_SVC("server closes.");
373         if (rdpsnd->device)
374                 IFCALL(rdpsnd->device->Start, rdpsnd->device);
375         rdpsnd->close_timestamp = get_mstime() + 2000;
376         rdpsnd->plugin.interval_ms = 10;
377 }
378
379 static void rdpsnd_process_message_setvolume(rdpsndPlugin* rdpsnd, STREAM* data_in)
380 {
381         uint32 dwVolume;
382
383         stream_read_uint32(data_in, dwVolume);
384         DEBUG_SVC("dwVolume 0x%X", dwVolume);
385         if (rdpsnd->device)
386                 IFCALL(rdpsnd->device->SetVolume, rdpsnd->device, dwVolume);
387 }
388
389 static void rdpsnd_process_receive(rdpSvcPlugin* plugin, STREAM* data_in)
390 {
391         rdpsndPlugin* rdpsnd = (rdpsndPlugin*)plugin;
392         uint8 msgType;
393         uint16 BodySize;
394
395         if (rdpsnd->expectingWave)
396         {
397                 rdpsnd_process_message_wave(rdpsnd, data_in);
398                 return;
399         }
400
401         stream_read_uint8(data_in, msgType); /* msgType */
402         stream_seek_uint8(data_in); /* bPad */
403         stream_read_uint16(data_in, BodySize);
404
405         DEBUG_SVC("msgType %d BodySize %d", msgType, BodySize);
406
407         switch (msgType)
408         {
409                 case SNDC_FORMATS:
410                         rdpsnd_process_message_formats(rdpsnd, data_in);
411                         break;
412                 case SNDC_TRAINING:
413                         rdpsnd_process_message_training(rdpsnd, data_in);
414                         break;
415                 case SNDC_WAVE:
416                         rdpsnd_process_message_wave_info(rdpsnd, data_in, BodySize);
417                         break;
418                 case SNDC_CLOSE:
419                         rdpsnd_process_message_close(rdpsnd);
420                         break;
421                 case SNDC_SETVOLUME:
422                         rdpsnd_process_message_setvolume(rdpsnd, data_in);
423                         break;
424                 default:
425                         DEBUG_WARN("unknown msgType %d", msgType);
426                         break;
427         }
428 }
429
430 static void rdpsnd_register_device_plugin(rdpsndPlugin* rdpsnd, rdpsndDevicePlugin* device)
431 {
432         if (rdpsnd->device)
433         {
434                 DEBUG_WARN("existing device, abort.");
435                 return;
436         }
437         rdpsnd->device = device;
438 }
439
440 static boolean rdpsnd_load_device_plugin(rdpsndPlugin* rdpsnd, const char* name, RDP_PLUGIN_DATA* data)
441 {
442         FREERDP_RDPSND_DEVICE_ENTRY_POINTS entryPoints;
443         PFREERDP_RDPSND_DEVICE_ENTRY entry;
444         char* fullname;
445
446         if (strrchr(name, '.') != NULL)
447                 entry = (PFREERDP_RDPSND_DEVICE_ENTRY)freerdp_load_plugin(name, RDPSND_DEVICE_EXPORT_FUNC_NAME);
448         else
449         {
450                 fullname = xzalloc(strlen(name) + 8);
451                 strcpy(fullname, "rdpsnd_");
452                 strcat(fullname, name);
453                 entry = (PFREERDP_RDPSND_DEVICE_ENTRY)freerdp_load_plugin(fullname, RDPSND_DEVICE_EXPORT_FUNC_NAME);
454                 xfree(fullname);
455         }
456         if (entry == NULL)
457         {
458                 return false;
459         }
460
461         entryPoints.rdpsnd = rdpsnd;
462         entryPoints.pRegisterRdpsndDevice = rdpsnd_register_device_plugin;
463         entryPoints.plugin_data = data;
464         if (entry(&entryPoints) != 0)
465         {
466                 DEBUG_WARN("%s entry returns error.", name);
467                 return false;
468         }
469         return true;
470 }
471
472 static void rdpsnd_process_plugin_data(rdpsndPlugin* rdpsnd, RDP_PLUGIN_DATA* data)
473 {
474         if (strcmp((char*)data->data[0], "format") == 0)
475         {
476                 rdpsnd->fixed_format = atoi(data->data[1]);
477         }
478         else if (strcmp((char*)data->data[0], "rate") == 0)
479         {
480                 rdpsnd->fixed_rate = atoi(data->data[1]);
481         }
482         else if (strcmp((char*)data->data[0], "channel") == 0)
483         {
484                 rdpsnd->fixed_channel = atoi(data->data[1]);
485         }
486         else if (strcmp((char*)data->data[0], "latency") == 0)
487         {
488                 rdpsnd->latency = atoi(data->data[1]);
489         }
490         else
491         {
492                 rdpsnd_load_device_plugin(rdpsnd, (char*)data->data[0], data);
493         }
494 }
495
496 static void rdpsnd_process_connect(rdpSvcPlugin* plugin)
497 {
498         rdpsndPlugin* rdpsnd = (rdpsndPlugin*)plugin;
499         RDP_PLUGIN_DATA* data;
500         RDP_PLUGIN_DATA default_data[2] = { { 0 }, { 0 } };
501
502         DEBUG_SVC("connecting");
503
504         plugin->interval_callback = rdpsnd_process_interval;
505
506         rdpsnd->data_out_list = list_new();
507         rdpsnd->latency = -1;
508
509         data = (RDP_PLUGIN_DATA*)plugin->channel_entry_points.pExtendedData;
510         while (data && data->size > 0)
511         {
512                 rdpsnd_process_plugin_data(rdpsnd, data);
513                 data = (RDP_PLUGIN_DATA*) (((void*) data) + data->size);
514         }
515
516         if (rdpsnd->device == NULL)
517         {
518                 default_data[0].size = sizeof(RDP_PLUGIN_DATA);
519                 default_data[0].data[0] = "pulse";
520                 default_data[0].data[1] = "";
521                 if (!rdpsnd_load_device_plugin(rdpsnd, "pulse", default_data))
522                 {
523                         default_data[0].data[0] = "alsa";
524                         default_data[0].data[1] = "default";
525                         rdpsnd_load_device_plugin(rdpsnd, "alsa", default_data);
526                 }
527         }
528         if (rdpsnd->device == NULL)
529         {
530                 DEBUG_WARN("no sound device.");
531         }
532 }
533
534 static void rdpsnd_process_event(rdpSvcPlugin* plugin, RDP_EVENT* event)
535 {
536         freerdp_event_free(event);
537 }
538
539 static void rdpsnd_process_terminate(rdpSvcPlugin* plugin)
540 {
541         rdpsndPlugin* rdpsnd = (rdpsndPlugin*)plugin;
542         struct data_out_item* item;
543
544         if (rdpsnd->device)
545                 IFCALL(rdpsnd->device->Free, rdpsnd->device);
546
547         while ((item = list_dequeue(rdpsnd->data_out_list)) != NULL)
548         {
549                 stream_free(item->data_out);
550                 xfree(item);
551         }
552         list_free(rdpsnd->data_out_list);
553
554         rdpsnd_free_supported_formats(rdpsnd);
555
556         xfree(plugin);
557 }
558
559 DEFINE_SVC_PLUGIN(rdpsnd, "rdpsnd",
560         CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP)
561