Initial commit - from Precise source
[freerdp-ubuntu-pcb-backport.git] / channels / drdynvc / audin / audin_main.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol client.
3  * Audio Input Redirection Virtual Channel
4  *
5  * Copyright 2010-2011 Vic Lee
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <freerdp/utils/memory.h>
24 #include <freerdp/utils/stream.h>
25 #include <freerdp/utils/load_plugin.h>
26
27 #include "audin_main.h"
28
29 #define MSG_SNDIN_VERSION       0x01
30 #define MSG_SNDIN_FORMATS       0x02
31 #define MSG_SNDIN_OPEN          0x03
32 #define MSG_SNDIN_OPEN_REPLY    0x04
33 #define MSG_SNDIN_DATA_INCOMING 0x05
34 #define MSG_SNDIN_DATA          0x06
35 #define MSG_SNDIN_FORMATCHANGE  0x07
36
37 typedef struct _AUDIN_LISTENER_CALLBACK AUDIN_LISTENER_CALLBACK;
38 struct _AUDIN_LISTENER_CALLBACK
39 {
40         IWTSListenerCallback iface;
41
42         IWTSPlugin* plugin;
43         IWTSVirtualChannelManager* channel_mgr;
44 };
45
46 typedef struct _AUDIN_CHANNEL_CALLBACK AUDIN_CHANNEL_CALLBACK;
47 struct _AUDIN_CHANNEL_CALLBACK
48 {
49         IWTSVirtualChannelCallback iface;
50
51         IWTSPlugin* plugin;
52         IWTSVirtualChannelManager* channel_mgr;
53         IWTSVirtualChannel* channel;
54
55         /**
56          * The supported format list sent back to the server, which needs to
57          * be stored as reference when the server sends the format index in
58          * Open PDU and Format Change PDU
59          */
60         audinFormat* formats;
61         int formats_count;
62 };
63
64 typedef struct _AUDIN_PLUGIN AUDIN_PLUGIN;
65 struct _AUDIN_PLUGIN
66 {
67         IWTSPlugin iface;
68
69         AUDIN_LISTENER_CALLBACK* listener_callback;
70
71         /* Parsed plugin data */
72         uint16 fixed_format;
73         uint16 fixed_channel;   
74         uint32 fixed_rate;
75
76         /* Device interface */
77         IAudinDevice* device;
78 };
79
80 static int audin_process_version(IWTSVirtualChannelCallback* pChannelCallback, STREAM* s)
81 {
82         int error;
83         STREAM* out;
84         uint32 Version;
85         AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
86
87         stream_read_uint32(s, Version);
88
89         DEBUG_DVC("Version=%d", Version);
90
91         out = stream_new(5);
92         stream_write_uint8(out, MSG_SNDIN_VERSION);
93         stream_write_uint32(out, Version);
94         error = callback->channel->Write(callback->channel, stream_get_length(s), stream_get_head(s), NULL);
95         stream_free(out);
96
97         return error;
98 }
99
100 static int audin_send_incoming_data_pdu(IWTSVirtualChannelCallback* pChannelCallback)
101 {
102         uint8 out_data[1];
103         AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
104
105         out_data[0] = MSG_SNDIN_DATA_INCOMING;
106         return callback->channel->Write(callback->channel, 1, out_data, NULL);
107 }
108
109 static int audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, STREAM* s)
110 {
111         AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
112         AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin;
113         uint32 i;
114         uint8* fm;
115         int error;
116         STREAM* out;
117         uint32 NumFormats;
118         audinFormat format;
119         uint32 cbSizeFormatsPacket;
120
121         stream_read_uint32(s, NumFormats);
122         DEBUG_DVC("NumFormats %d", NumFormats);
123         if ((NumFormats < 1) || (NumFormats > 1000))
124         {
125                 DEBUG_WARN("bad NumFormats %d", NumFormats);
126                 return 1;
127         }
128         stream_seek_uint32(s); /* cbSizeFormatsPacket */
129
130         callback->formats = (audinFormat*) xzalloc(NumFormats * sizeof(audinFormat));
131
132         out = stream_new(9);
133         stream_seek(out, 9);
134
135         /* SoundFormats (variable) */
136         for (i = 0; i < NumFormats; i++)
137         {
138                 stream_get_mark(s, fm);
139                 stream_read_uint16(s, format.wFormatTag);
140                 stream_read_uint16(s, format.nChannels);
141                 stream_read_uint32(s, format.nSamplesPerSec);
142                 stream_seek_uint32(s); /* nAvgBytesPerSec */
143                 stream_read_uint16(s, format.nBlockAlign);
144                 stream_read_uint16(s, format.wBitsPerSample);
145                 stream_read_uint16(s, format.cbSize);
146                 format.data = stream_get_tail(s);
147                 stream_seek(s, format.cbSize);
148                 
149                 DEBUG_DVC("wFormatTag=%d nChannels=%d nSamplesPerSec=%d "
150                         "nBlockAlign=%d wBitsPerSample=%d cbSize=%d",
151                         format.wFormatTag, format.nChannels, format.nSamplesPerSec,
152                         format.nBlockAlign, format.wBitsPerSample, format.cbSize);
153
154                 if (audin->fixed_format > 0 && audin->fixed_format != format.wFormatTag)
155                         continue;
156                 if (audin->fixed_channel > 0 && audin->fixed_channel != format.nChannels)
157                         continue;
158                 if (audin->fixed_rate > 0 && audin->fixed_rate != format.nSamplesPerSec)
159                         continue;
160                 if (audin->device && audin->device->FormatSupported(audin->device, &format))
161                 {
162                         DEBUG_DVC("format ok");
163
164                         /* Store the agreed format in the corresponding index */
165                         callback->formats[callback->formats_count++] = format;
166                         /* Put the format to output buffer */
167                         stream_check_size(out, 18 + format.cbSize);
168                         stream_write(out, fm, 18 + format.cbSize);
169                 }
170         }
171
172         audin_send_incoming_data_pdu(pChannelCallback);
173
174         cbSizeFormatsPacket = stream_get_pos(out);
175         stream_set_pos(out, 0);
176
177         stream_write_uint8(out, MSG_SNDIN_FORMATS); /* Header (1 byte) */
178         stream_write_uint32(out, callback->formats_count); /* NumFormats (4 bytes) */
179         stream_write_uint32(out, cbSizeFormatsPacket); /* cbSizeFormatsPacket (4 bytes) */
180
181         error = callback->channel->Write(callback->channel, cbSizeFormatsPacket, stream_get_head(out), NULL);
182         stream_free(out);
183
184         return error;
185 }
186
187 static int audin_send_format_change_pdu(IWTSVirtualChannelCallback* pChannelCallback, uint32 NewFormat)
188 {
189         int error;
190         STREAM* out;
191         AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
192
193         out = stream_new(5);
194         stream_write_uint8(out, MSG_SNDIN_FORMATCHANGE);
195         stream_write_uint32(out, NewFormat);
196         error = callback->channel->Write(callback->channel, 5, stream_get_head(out), NULL);
197         stream_free(out);
198
199         return error;
200 }
201
202 static int audin_send_open_reply_pdu(IWTSVirtualChannelCallback* pChannelCallback, uint32 Result)
203 {
204         int error;
205         STREAM* out;
206         AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
207
208         out = stream_new(5);
209         stream_write_uint8(out, MSG_SNDIN_OPEN_REPLY);
210         stream_write_uint32(out, Result);
211         error = callback->channel->Write(callback->channel, 5, stream_get_head(out), NULL);
212         stream_free(out);
213
214         return error;
215 }
216
217 static boolean audin_receive_wave_data(uint8* data, int size, void* user_data)
218 {
219         int error;
220         STREAM* out;
221         AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) user_data;
222
223         error = audin_send_incoming_data_pdu((IWTSVirtualChannelCallback*) callback);
224
225         if (error != 0)
226                 return false;
227
228         out = stream_new(size + 1);
229         stream_write_uint8(out, MSG_SNDIN_DATA);
230         stream_write(out, data, size);
231         error = callback->channel->Write(callback->channel, stream_get_length(out), stream_get_head(out), NULL);
232         stream_free(out);
233
234         return (error == 0 ? true : false);
235 }
236
237 static int audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, STREAM* s)
238 {
239         AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
240         AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin;
241         audinFormat* format;
242         uint32 initialFormat;
243         uint32 FramesPerPacket;
244
245         stream_read_uint32(s, FramesPerPacket);
246         stream_read_uint32(s, initialFormat);
247
248         DEBUG_DVC("FramesPerPacket=%d initialFormat=%d",
249                 FramesPerPacket, initialFormat);
250
251         if (initialFormat >= callback->formats_count)
252         {
253                 DEBUG_WARN("invalid format index %d (total %d)",
254                         initialFormat, callback->formats_count);
255                 return 1;
256         }
257
258         format = &callback->formats[initialFormat];
259         if (audin->device)
260         {
261                 IFCALL(audin->device->SetFormat, audin->device, format, FramesPerPacket);
262                 IFCALL(audin->device->Open, audin->device, audin_receive_wave_data, callback);
263         }
264
265         audin_send_format_change_pdu(pChannelCallback, initialFormat);
266         audin_send_open_reply_pdu(pChannelCallback, 0);
267
268         return 0;
269 }
270
271 static int audin_process_format_change(IWTSVirtualChannelCallback* pChannelCallback, STREAM* s)
272 {
273         AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
274         AUDIN_PLUGIN * audin = (AUDIN_PLUGIN*) callback->plugin;
275         uint32 NewFormat;
276         audinFormat* format;
277
278         stream_read_uint32(s, NewFormat);
279
280         DEBUG_DVC("NewFormat=%d", NewFormat);
281
282         if (NewFormat >= callback->formats_count)
283         {
284                 DEBUG_WARN("invalid format index %d (total %d)",
285                         NewFormat, callback->formats_count);
286                 return 1;
287         }
288
289         format = &callback->formats[NewFormat];
290
291         if (audin->device)
292         {
293                 IFCALL(audin->device->Close, audin->device);
294                 IFCALL(audin->device->SetFormat, audin->device, format, 0);
295                 IFCALL(audin->device->Open, audin->device, audin_receive_wave_data, callback);
296         }
297
298         audin_send_format_change_pdu(pChannelCallback, NewFormat);
299
300         return 0;
301 }
302
303 static int audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, uint32 cbSize, uint8* pBuffer)
304 {
305         int error;
306         STREAM* s;
307         uint8 MessageId;
308
309         s = stream_new(0);
310         stream_attach(s, pBuffer, cbSize);
311
312         stream_read_uint8(s, MessageId);
313
314         DEBUG_DVC("MessageId=0x%x", MessageId);
315
316         switch (MessageId)
317         {
318                 case MSG_SNDIN_VERSION:
319                         error = audin_process_version(pChannelCallback, s);
320                         break;
321
322                 case MSG_SNDIN_FORMATS:
323                         error = audin_process_formats(pChannelCallback, s);
324                         break;
325
326                 case MSG_SNDIN_OPEN:
327                         error = audin_process_open(pChannelCallback, s);
328                         break;
329
330                 case MSG_SNDIN_FORMATCHANGE:
331                         error = audin_process_format_change(pChannelCallback, s);
332                         break;
333
334                 default:
335                         DEBUG_WARN("unknown MessageId=0x%x", MessageId);
336                         error = 1;
337                         break;
338         }
339
340         stream_detach(s);
341         stream_free(s);
342
343         return error;
344 }
345
346 static int audin_on_close(IWTSVirtualChannelCallback* pChannelCallback)
347 {
348         AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
349         AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin;
350
351         DEBUG_DVC("");
352
353         if (audin->device)
354                 IFCALL(audin->device->Close, audin->device);
355
356         xfree(callback->formats);
357         xfree(callback);
358
359         return 0;
360 }
361
362 static int audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
363         IWTSVirtualChannel* pChannel, uint8* Data, int* pbAccept,
364         IWTSVirtualChannelCallback** ppCallback)
365 {
366         AUDIN_CHANNEL_CALLBACK* callback;
367         AUDIN_LISTENER_CALLBACK* listener_callback = (AUDIN_LISTENER_CALLBACK*) pListenerCallback;
368
369         DEBUG_DVC("");
370
371         callback = xnew(AUDIN_CHANNEL_CALLBACK);
372
373         callback->iface.OnDataReceived = audin_on_data_received;
374         callback->iface.OnClose = audin_on_close;
375         callback->plugin = listener_callback->plugin;
376         callback->channel_mgr = listener_callback->channel_mgr;
377         callback->channel = pChannel;
378
379         *ppCallback = (IWTSVirtualChannelCallback*) callback;
380
381         return 0;
382 }
383
384 static int audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
385 {
386         AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
387
388         DEBUG_DVC("");
389
390         audin->listener_callback = xnew(AUDIN_LISTENER_CALLBACK);
391
392         audin->listener_callback->iface.OnNewChannelConnection = audin_on_new_channel_connection;
393         audin->listener_callback->plugin = pPlugin;
394         audin->listener_callback->channel_mgr = pChannelMgr;
395
396         return pChannelMgr->CreateListener(pChannelMgr, "AUDIO_INPUT", 0,
397                 (IWTSListenerCallback*) audin->listener_callback, NULL);
398 }
399
400 static int audin_plugin_terminated(IWTSPlugin* pPlugin)
401 {
402         AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
403
404         DEBUG_DVC("");
405
406         if (audin->device)
407         {
408                 IFCALL(audin->device->Close, audin->device);
409                 IFCALL(audin->device->Free, audin->device);
410                 audin->device = NULL;
411         }
412
413         xfree(audin->listener_callback);
414         xfree(audin);
415
416         return 0;
417 }
418
419 static void audin_register_device_plugin(IWTSPlugin* pPlugin, IAudinDevice* device)
420 {
421         AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
422
423         if (audin->device)
424         {
425                 DEBUG_WARN("existing device, abort.");
426                 return;
427         }
428
429         DEBUG_DVC("device registered.");
430
431         audin->device = device;
432 }
433
434 static boolean audin_load_device_plugin(IWTSPlugin* pPlugin, const char* name, RDP_PLUGIN_DATA* data)
435 {
436         char* fullname;
437         PFREERDP_AUDIN_DEVICE_ENTRY entry;
438         FREERDP_AUDIN_DEVICE_ENTRY_POINTS entryPoints;
439
440         if (strrchr(name, '.') != NULL)
441         {
442                 entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_plugin(name, AUDIN_DEVICE_EXPORT_FUNC_NAME);
443         }
444         else
445         {
446                 fullname = xzalloc(strlen(name) + 8);
447                 strcpy(fullname, "audin_");
448                 strcat(fullname, name);
449                 entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_plugin(fullname, AUDIN_DEVICE_EXPORT_FUNC_NAME);
450                 xfree(fullname);
451         }
452
453         if (entry == NULL)
454                 return false;
455
456         entryPoints.plugin = pPlugin;
457         entryPoints.pRegisterAudinDevice = audin_register_device_plugin;
458         entryPoints.plugin_data = data;
459
460         if (entry(&entryPoints) != 0)
461         {
462                 DEBUG_WARN("%s entry returns error.", name);
463                 return false;
464         }
465
466         return true;
467 }
468
469 static boolean audin_process_plugin_data(IWTSPlugin* pPlugin, RDP_PLUGIN_DATA* data)
470 {
471         boolean ret;
472         AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
473         RDP_PLUGIN_DATA default_data[2] = { { 0 }, { 0 } };
474
475         if (data->data[0] && (strcmp((char*)data->data[0], "audin") == 0 || strstr((char*) data->data[0], "/audin.") != NULL))
476         {
477                 if (data->data[1] && strcmp((char*)data->data[1], "format") == 0)
478                 {
479                         audin->fixed_format = atoi(data->data[2]);
480                         return true;
481                 }
482                 else if (data->data[1] && strcmp((char*)data->data[1], "rate") == 0)
483                 {
484                         audin->fixed_rate = atoi(data->data[2]);
485                         return true;
486                 }
487                 else if (data->data[1] && strcmp((char*)data->data[1], "channel") == 0)
488                 {
489                         audin->fixed_channel = atoi(data->data[2]);
490                         return true;
491                 }
492                 else if (data->data[1] && ((char*)data->data[1])[0])
493                 {
494                         return audin_load_device_plugin(pPlugin, (char*) data->data[1], data);
495                 }
496                 else
497                 {
498                         default_data[0].size = sizeof(RDP_PLUGIN_DATA);
499                         default_data[0].data[0] = "audin";
500                         default_data[0].data[1] = "pulse";
501                         default_data[0].data[2] = "";
502
503                         ret = audin_load_device_plugin(pPlugin, "pulse", default_data);
504
505                         if (!ret)
506                         {
507                                 default_data[0].size = sizeof(RDP_PLUGIN_DATA);
508                                 default_data[0].data[0] = "audin";
509                                 default_data[0].data[1] = "alsa";
510                                 default_data[0].data[2] = "default";
511                                 ret = audin_load_device_plugin(pPlugin, "alsa", default_data);
512                         }
513
514                         return ret;
515                 }
516         }
517
518         return true;
519 }
520
521 int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
522 {
523         int error = 0;
524         AUDIN_PLUGIN* audin;
525
526         audin = (AUDIN_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "audin");
527
528         if (audin == NULL)
529         {
530                 audin = xnew(AUDIN_PLUGIN);
531
532                 audin->iface.Initialize = audin_plugin_initialize;
533                 audin->iface.Connected = NULL;
534                 audin->iface.Disconnected = NULL;
535                 audin->iface.Terminated = audin_plugin_terminated;
536                 error = pEntryPoints->RegisterPlugin(pEntryPoints, "audin", (IWTSPlugin*) audin);
537         }
538
539         if (error == 0)
540                 audin_process_plugin_data((IWTSPlugin*) audin, pEntryPoints->GetPluginData(pEntryPoints));
541
542         return error;
543 }
544