22 #include <freerdp/config.h>
24 #include <winpr/assert.h>
29 #include <winpr/crt.h>
30 #include <winpr/cmdline.h>
32 #include <freerdp/freerdp.h>
33 #include <freerdp/addin.h>
34 #include <freerdp/channels/rdpsnd.h>
36 #include <SLES/OpenSLES.h>
37 #include <freerdp/client/audin.h>
39 #include "audin_main.h"
40 #include "opensl_io.h"
50 UINT32 frames_per_packet;
52 UINT32 bytes_per_channel;
58 rdpContext* rdpcontext;
60 } AudinOpenSLESDevice;
62 static UINT audin_opensles_close(IAudinDevice* device);
64 static void audin_receive(
void* context,
const void* data,
size_t size)
67 AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)context;
69 if (!opensles || !data)
71 WLog_ERR(TAG,
"Invalid arguments context=%p, data=%p", opensles, data);
75 error = opensles->receive(&opensles->format, data, size, opensles->user_data);
77 if (error && opensles->rdpcontext)
78 setChannelError(opensles->rdpcontext, error,
"audin_receive reported an error");
86 static UINT audin_opensles_free(IAudinDevice* device)
88 AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device;
91 return ERROR_INVALID_PARAMETER;
93 WLog_Print(opensles->log, WLOG_DEBUG,
"device=%p", (
void*)device);
95 free(opensles->device_name);
100 static BOOL audin_opensles_format_supported(IAudinDevice* device,
const AUDIO_FORMAT* format)
102 AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device;
104 if (!opensles || !format)
107 WLog_Print(opensles->log, WLOG_DEBUG,
"device=%p, format=%p", (
void*)opensles, (
void*)format);
108 WINPR_ASSERT(format);
110 switch (format->wFormatTag)
112 case WAVE_FORMAT_PCM:
113 if (format->cbSize == 0 && (format->nSamplesPerSec <= 48000) &&
114 (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) &&
115 (format->nChannels >= 1 && format->nChannels <= 2))
123 WLog_Print(opensles->log, WLOG_DEBUG,
"Encoding '%s' [0x%04" PRIX16
"] not supported",
124 audio_format_get_tag_string(format->wFormatTag), format->wFormatTag);
136 static UINT audin_opensles_set_format(IAudinDevice* device,
const AUDIO_FORMAT* format,
137 UINT32 FramesPerPacket)
139 AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device;
141 if (!opensles || !format)
142 return ERROR_INVALID_PARAMETER;
144 WLog_Print(opensles->log, WLOG_DEBUG,
"device=%p, format=%p, FramesPerPacket=%" PRIu32
"",
145 (
void*)device, (
void*)format, FramesPerPacket);
146 WINPR_ASSERT(format);
148 opensles->format = *format;
150 switch (format->wFormatTag)
152 case WAVE_FORMAT_PCM:
153 opensles->frames_per_packet = FramesPerPacket;
155 switch (format->wBitsPerSample)
158 opensles->bytes_per_channel = 1;
162 opensles->bytes_per_channel = 1;
166 opensles->bytes_per_channel = 2;
170 return ERROR_UNSUPPORTED_TYPE;
176 WLog_Print(opensles->log, WLOG_ERROR,
177 "Encoding '%" PRIu16
"' [%04" PRIX16
"] not supported", format->wFormatTag,
179 return ERROR_UNSUPPORTED_TYPE;
182 WLog_Print(opensles->log, WLOG_DEBUG,
"frames_per_packet=%" PRIu32,
183 opensles->frames_per_packet);
184 return CHANNEL_RC_OK;
192 static UINT audin_opensles_open(IAudinDevice* device, AudinReceive receive,
void* user_data)
194 AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device;
196 if (!opensles || !receive || !user_data)
197 return ERROR_INVALID_PARAMETER;
199 WLog_Print(opensles->log, WLOG_DEBUG,
"device=%p, receive=%p, user_data=%p", (
void*)device,
200 (
void*)receive, (
void*)user_data);
202 if (opensles->stream)
205 if (!(opensles->stream = android_OpenRecDevice(
206 opensles, audin_receive, opensles->format.nSamplesPerSec, opensles->format.nChannels,
207 opensles->frames_per_packet, opensles->format.wBitsPerSample)))
209 WLog_Print(opensles->log, WLOG_ERROR,
"android_OpenRecDevice failed!");
213 opensles->receive = receive;
214 opensles->user_data = user_data;
215 return CHANNEL_RC_OK;
217 audin_opensles_close(device);
218 return ERROR_INTERNAL_ERROR;
226 UINT audin_opensles_close(IAudinDevice* device)
228 AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device;
231 return ERROR_INVALID_PARAMETER;
233 WLog_Print(opensles->log, WLOG_DEBUG,
"device=%p", (
void*)device);
234 android_CloseRecDevice(opensles->stream);
235 opensles->receive = NULL;
236 opensles->user_data = NULL;
237 opensles->stream = NULL;
238 return CHANNEL_RC_OK;
246 static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device,
const ADDIN_ARGV* args)
251 AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device;
253 {
"dev", COMMAND_LINE_VALUE_REQUIRED,
"<device>", NULL, NULL, -1, NULL,
254 "audio device name" },
255 { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
258 WLog_Print(opensles->log, WLOG_DEBUG,
"device=%p, args=%p", (
void*)device, (
void*)args);
260 COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
261 status = CommandLineParseArgumentsA(args->argc, args->argv, audin_opensles_args, flags,
262 opensles, NULL, NULL);
267 arg = audin_opensles_args;
271 if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
274 CommandLineSwitchStart(arg) CommandLineSwitchCase(arg,
"dev")
276 opensles->device_name = _strdup(arg->Value);
278 if (!opensles->device_name)
280 WLog_Print(opensles->log, WLOG_ERROR,
"_strdup failed!");
281 return CHANNEL_RC_NO_MEMORY;
284 CommandLineSwitchEnd(arg)
285 }
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
287 return CHANNEL_RC_OK;
295 FREERDP_ENTRY_POINT(UINT VCAPITYPE opensles_freerdp_audin_client_subsystem_entry(
299 AudinOpenSLESDevice* opensles;
301 opensles = (AudinOpenSLESDevice*)calloc(1,
sizeof(AudinOpenSLESDevice));
305 WLog_ERR(TAG,
"calloc failed!");
306 return CHANNEL_RC_NO_MEMORY;
309 opensles->log = WLog_Get(TAG);
310 opensles->iface.Open = audin_opensles_open;
311 opensles->iface.FormatSupported = audin_opensles_format_supported;
312 opensles->iface.SetFormat = audin_opensles_set_format;
313 opensles->iface.Close = audin_opensles_close;
314 opensles->iface.Free = audin_opensles_free;
315 opensles->rdpcontext = pEntryPoints->rdpcontext;
316 args = pEntryPoints->args;
318 if ((error = audin_opensles_parse_addin_args(opensles, args)))
320 WLog_Print(opensles->log, WLOG_ERROR,
321 "audin_opensles_parse_addin_args failed with errorcode %" PRIu32
"!", error);
325 if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*)opensles)))
327 WLog_Print(opensles->log, WLOG_ERROR,
"RegisterAudinDevice failed with error %" PRIu32
"!",
332 return CHANNEL_RC_OK;