2 * FreeRDP: A Remote Desktop Protocol client.
3 * Audio Input Redirection Virtual Channel
5 * Copyright 2010-2011 Vic Lee
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #include <freerdp/utils/memory.h>
24 #include <freerdp/utils/stream.h>
25 #include <freerdp/utils/load_plugin.h>
27 #include "audin_main.h"
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
37 typedef struct _AUDIN_LISTENER_CALLBACK AUDIN_LISTENER_CALLBACK;
38 struct _AUDIN_LISTENER_CALLBACK
40 IWTSListenerCallback iface;
43 IWTSVirtualChannelManager* channel_mgr;
46 typedef struct _AUDIN_CHANNEL_CALLBACK AUDIN_CHANNEL_CALLBACK;
47 struct _AUDIN_CHANNEL_CALLBACK
49 IWTSVirtualChannelCallback iface;
52 IWTSVirtualChannelManager* channel_mgr;
53 IWTSVirtualChannel* channel;
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
64 typedef struct _AUDIN_PLUGIN AUDIN_PLUGIN;
69 AUDIN_LISTENER_CALLBACK* listener_callback;
71 /* Parsed plugin data */
76 /* Device interface */
80 static int audin_process_version(IWTSVirtualChannelCallback* pChannelCallback, STREAM* s)
85 AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
87 stream_read_uint32(s, Version);
89 DEBUG_DVC("Version=%d", Version);
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);
100 static int audin_send_incoming_data_pdu(IWTSVirtualChannelCallback* pChannelCallback)
103 AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
105 out_data[0] = MSG_SNDIN_DATA_INCOMING;
106 return callback->channel->Write(callback->channel, 1, out_data, NULL);
109 static int audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, STREAM* s)
111 AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
112 AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin;
119 uint32 cbSizeFormatsPacket;
121 stream_read_uint32(s, NumFormats);
122 DEBUG_DVC("NumFormats %d", NumFormats);
123 if ((NumFormats < 1) || (NumFormats > 1000))
125 DEBUG_WARN("bad NumFormats %d", NumFormats);
128 stream_seek_uint32(s); /* cbSizeFormatsPacket */
130 callback->formats = (audinFormat*) xzalloc(NumFormats * sizeof(audinFormat));
135 /* SoundFormats (variable) */
136 for (i = 0; i < NumFormats; i++)
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);
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);
154 if (audin->fixed_format > 0 && audin->fixed_format != format.wFormatTag)
156 if (audin->fixed_channel > 0 && audin->fixed_channel != format.nChannels)
158 if (audin->fixed_rate > 0 && audin->fixed_rate != format.nSamplesPerSec)
160 if (audin->device && audin->device->FormatSupported(audin->device, &format))
162 DEBUG_DVC("format ok");
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);
172 audin_send_incoming_data_pdu(pChannelCallback);
174 cbSizeFormatsPacket = stream_get_pos(out);
175 stream_set_pos(out, 0);
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) */
181 error = callback->channel->Write(callback->channel, cbSizeFormatsPacket, stream_get_head(out), NULL);
187 static int audin_send_format_change_pdu(IWTSVirtualChannelCallback* pChannelCallback, uint32 NewFormat)
191 AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
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);
202 static int audin_send_open_reply_pdu(IWTSVirtualChannelCallback* pChannelCallback, uint32 Result)
206 AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
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);
217 static boolean audin_receive_wave_data(uint8* data, int size, void* user_data)
221 AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) user_data;
223 error = audin_send_incoming_data_pdu((IWTSVirtualChannelCallback*) callback);
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);
234 return (error == 0 ? true : false);
237 static int audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, STREAM* s)
239 AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
240 AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin;
242 uint32 initialFormat;
243 uint32 FramesPerPacket;
245 stream_read_uint32(s, FramesPerPacket);
246 stream_read_uint32(s, initialFormat);
248 DEBUG_DVC("FramesPerPacket=%d initialFormat=%d",
249 FramesPerPacket, initialFormat);
251 if (initialFormat >= callback->formats_count)
253 DEBUG_WARN("invalid format index %d (total %d)",
254 initialFormat, callback->formats_count);
258 format = &callback->formats[initialFormat];
261 IFCALL(audin->device->SetFormat, audin->device, format, FramesPerPacket);
262 IFCALL(audin->device->Open, audin->device, audin_receive_wave_data, callback);
265 audin_send_format_change_pdu(pChannelCallback, initialFormat);
266 audin_send_open_reply_pdu(pChannelCallback, 0);
271 static int audin_process_format_change(IWTSVirtualChannelCallback* pChannelCallback, STREAM* s)
273 AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
274 AUDIN_PLUGIN * audin = (AUDIN_PLUGIN*) callback->plugin;
278 stream_read_uint32(s, NewFormat);
280 DEBUG_DVC("NewFormat=%d", NewFormat);
282 if (NewFormat >= callback->formats_count)
284 DEBUG_WARN("invalid format index %d (total %d)",
285 NewFormat, callback->formats_count);
289 format = &callback->formats[NewFormat];
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);
298 audin_send_format_change_pdu(pChannelCallback, NewFormat);
303 static int audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, uint32 cbSize, uint8* pBuffer)
310 stream_attach(s, pBuffer, cbSize);
312 stream_read_uint8(s, MessageId);
314 DEBUG_DVC("MessageId=0x%x", MessageId);
318 case MSG_SNDIN_VERSION:
319 error = audin_process_version(pChannelCallback, s);
322 case MSG_SNDIN_FORMATS:
323 error = audin_process_formats(pChannelCallback, s);
327 error = audin_process_open(pChannelCallback, s);
330 case MSG_SNDIN_FORMATCHANGE:
331 error = audin_process_format_change(pChannelCallback, s);
335 DEBUG_WARN("unknown MessageId=0x%x", MessageId);
346 static int audin_on_close(IWTSVirtualChannelCallback* pChannelCallback)
348 AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
349 AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin;
354 IFCALL(audin->device->Close, audin->device);
356 xfree(callback->formats);
362 static int audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
363 IWTSVirtualChannel* pChannel, uint8* Data, int* pbAccept,
364 IWTSVirtualChannelCallback** ppCallback)
366 AUDIN_CHANNEL_CALLBACK* callback;
367 AUDIN_LISTENER_CALLBACK* listener_callback = (AUDIN_LISTENER_CALLBACK*) pListenerCallback;
371 callback = xnew(AUDIN_CHANNEL_CALLBACK);
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;
379 *ppCallback = (IWTSVirtualChannelCallback*) callback;
384 static int audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
386 AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
390 audin->listener_callback = xnew(AUDIN_LISTENER_CALLBACK);
392 audin->listener_callback->iface.OnNewChannelConnection = audin_on_new_channel_connection;
393 audin->listener_callback->plugin = pPlugin;
394 audin->listener_callback->channel_mgr = pChannelMgr;
396 return pChannelMgr->CreateListener(pChannelMgr, "AUDIO_INPUT", 0,
397 (IWTSListenerCallback*) audin->listener_callback, NULL);
400 static int audin_plugin_terminated(IWTSPlugin* pPlugin)
402 AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
408 IFCALL(audin->device->Close, audin->device);
409 IFCALL(audin->device->Free, audin->device);
410 audin->device = NULL;
413 xfree(audin->listener_callback);
419 static void audin_register_device_plugin(IWTSPlugin* pPlugin, IAudinDevice* device)
421 AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
425 DEBUG_WARN("existing device, abort.");
429 DEBUG_DVC("device registered.");
431 audin->device = device;
434 static boolean audin_load_device_plugin(IWTSPlugin* pPlugin, const char* name, RDP_PLUGIN_DATA* data)
437 PFREERDP_AUDIN_DEVICE_ENTRY entry;
438 FREERDP_AUDIN_DEVICE_ENTRY_POINTS entryPoints;
440 if (strrchr(name, '.') != NULL)
442 entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_plugin(name, AUDIN_DEVICE_EXPORT_FUNC_NAME);
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);
456 entryPoints.plugin = pPlugin;
457 entryPoints.pRegisterAudinDevice = audin_register_device_plugin;
458 entryPoints.plugin_data = data;
460 if (entry(&entryPoints) != 0)
462 DEBUG_WARN("%s entry returns error.", name);
469 static boolean audin_process_plugin_data(IWTSPlugin* pPlugin, RDP_PLUGIN_DATA* data)
472 AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
473 RDP_PLUGIN_DATA default_data[2] = { { 0 }, { 0 } };
475 if (data->data[0] && (strcmp((char*)data->data[0], "audin") == 0 || strstr((char*) data->data[0], "/audin.") != NULL))
477 if (data->data[1] && strcmp((char*)data->data[1], "format") == 0)
479 audin->fixed_format = atoi(data->data[2]);
482 else if (data->data[1] && strcmp((char*)data->data[1], "rate") == 0)
484 audin->fixed_rate = atoi(data->data[2]);
487 else if (data->data[1] && strcmp((char*)data->data[1], "channel") == 0)
489 audin->fixed_channel = atoi(data->data[2]);
492 else if (data->data[1] && ((char*)data->data[1])[0])
494 return audin_load_device_plugin(pPlugin, (char*) data->data[1], data);
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] = "";
503 ret = audin_load_device_plugin(pPlugin, "pulse", default_data);
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);
521 int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
526 audin = (AUDIN_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "audin");
530 audin = xnew(AUDIN_PLUGIN);
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);
540 audin_process_plugin_data((IWTSPlugin*) audin, pEntryPoints->GetPluginData(pEntryPoints));