22 #include <freerdp/config.h>
24 #include <winpr/assert.h>
31 #include <winpr/crt.h>
32 #include <winpr/cmdline.h>
33 #include <winpr/sysinfo.h>
34 #include <winpr/collections.h>
36 #include <freerdp/types.h>
37 #include <freerdp/channels/log.h>
39 #include "opensl_io.h"
40 #include "rdpsnd_main.h"
44 rdpsndDevicePlugin device;
58 } rdpsndopenslesPlugin;
60 static int rdpsnd_opensles_volume_to_millibel(
unsigned short level,
int max)
62 const int min = SL_MILLIBEL_MIN;
63 const int step = max - min;
64 const int rc = (level * step / 0xFFFF) + min;
65 DEBUG_SND(
"level=%hu, min=%d, max=%d, step=%d, result=%d", level, min, max, step, rc);
69 static unsigned short rdpsnd_opensles_millibel_to_volume(
int millibel,
int max)
71 const int min = SL_MILLIBEL_MIN;
72 const int range = max - min;
73 const int rc = ((millibel - min) * 0xFFFF + range / 2 + 1) / range;
74 DEBUG_SND(
"millibel=%d, min=%d, max=%d, range=%d, result=%d", millibel, min, max, range, rc);
78 static bool rdpsnd_opensles_check_handle(
const rdpsndopenslesPlugin* hdl)
93 static BOOL rdpsnd_opensles_set_volume(rdpsndDevicePlugin* device, UINT32 volume);
95 static int rdpsnd_opensles_set_params(rdpsndopenslesPlugin* opensles)
97 DEBUG_SND(
"opensles=%p", (
void*)opensles);
99 if (!rdpsnd_opensles_check_handle(opensles))
102 if (opensles->stream)
103 android_CloseAudioDevice(opensles->stream);
105 opensles->stream = android_OpenAudioDevice(opensles->rate, opensles->channels, 20);
109 static BOOL rdpsnd_opensles_set_format(rdpsndDevicePlugin* device,
const AUDIO_FORMAT* format,
112 rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*)device;
113 rdpsnd_opensles_check_handle(opensles);
114 DEBUG_SND(
"opensles=%p format=%p, latency=%" PRIu32, (
void*)opensles, (
void*)format, latency);
118 DEBUG_SND(
"format=%" PRIu16
", cbsize=%" PRIu16
", samples=%" PRIu32
", bits=%" PRIu16
119 ", channels=%" PRIu16
", align=%" PRIu16
"",
120 format->wFormatTag, format->cbSize, format->nSamplesPerSec,
121 format->wBitsPerSample, format->nChannels, format->nBlockAlign);
122 opensles->rate = format->nSamplesPerSec;
123 opensles->channels = format->nChannels;
124 opensles->format = format->wFormatTag;
125 opensles->wformat = format->wFormatTag;
126 opensles->block_size = format->nBlockAlign;
129 opensles->latency = latency;
130 return (rdpsnd_opensles_set_params(opensles) == 0);
133 static BOOL rdpsnd_opensles_open(rdpsndDevicePlugin* device,
const AUDIO_FORMAT* format,
136 rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*)device;
137 DEBUG_SND(
"opensles=%p format=%p, latency=%" PRIu32
", rate=%" PRIu32
"", (
void*)opensles,
138 (
void*)format, latency, opensles->rate);
140 if (rdpsnd_opensles_check_handle(opensles))
143 opensles->stream = android_OpenAudioDevice(opensles->rate, opensles->channels, 20);
144 WINPR_ASSERT(opensles->stream);
146 if (!opensles->stream)
147 WLog_ERR(TAG,
"android_OpenAudioDevice failed");
149 rdpsnd_opensles_set_volume(device, opensles->volume);
151 return rdpsnd_opensles_set_format(device, format, latency);
154 static void rdpsnd_opensles_close(rdpsndDevicePlugin* device)
156 rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*)device;
157 DEBUG_SND(
"opensles=%p", (
void*)opensles);
159 if (!rdpsnd_opensles_check_handle(opensles))
162 android_CloseAudioDevice(opensles->stream);
163 opensles->stream = NULL;
166 static void rdpsnd_opensles_free(rdpsndDevicePlugin* device)
168 rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*)device;
169 DEBUG_SND(
"opensles=%p", (
void*)opensles);
170 WINPR_ASSERT(opensles);
171 WINPR_ASSERT(opensles->device_name);
172 free(opensles->device_name);
176 static BOOL rdpsnd_opensles_format_supported(rdpsndDevicePlugin* device,
const AUDIO_FORMAT* format)
178 DEBUG_SND(
"format=%" PRIu16
", cbsize=%" PRIu16
", samples=%" PRIu32
", bits=%" PRIu16
179 ", channels=%" PRIu16
", align=%" PRIu16
"",
180 format->wFormatTag, format->cbSize, format->nSamplesPerSec, format->wBitsPerSample,
181 format->nChannels, format->nBlockAlign);
182 WINPR_ASSERT(device);
183 WINPR_ASSERT(format);
185 switch (format->wFormatTag)
187 case WAVE_FORMAT_PCM:
188 if (format->cbSize == 0 && format->nSamplesPerSec <= 48000 &&
189 (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) &&
190 (format->nChannels == 1 || format->nChannels == 2))
204 static UINT32 rdpsnd_opensles_get_volume(rdpsndDevicePlugin* device)
206 rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*)device;
207 DEBUG_SND(
"opensles=%p", (
void*)opensles);
208 WINPR_ASSERT(opensles);
210 if (opensles->stream)
212 const int max = android_GetOutputVolumeMax(opensles->stream);
213 const int rc = android_GetOutputVolume(opensles->stream);
215 if (android_GetOutputMute(opensles->stream))
216 opensles->volume = 0;
219 const unsigned short vol = rdpsnd_opensles_millibel_to_volume(rc, max);
220 opensles->volume = (vol << 16) | (vol & 0xFFFF);
224 return opensles->volume;
227 static BOOL rdpsnd_opensles_set_volume(rdpsndDevicePlugin* device, UINT32 value)
229 rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*)device;
230 DEBUG_SND(
"opensles=%p, value=%" PRIu32
"", (
void*)opensles, value);
231 WINPR_ASSERT(opensles);
232 opensles->volume = value;
234 if (opensles->stream)
236 if (0 == opensles->volume)
237 return android_SetOutputMute(opensles->stream,
true);
240 const int max = android_GetOutputVolumeMax(opensles->stream);
241 const int vol = rdpsnd_opensles_volume_to_millibel(value & 0xFFFF, max);
243 if (!android_SetOutputMute(opensles->stream,
false))
246 if (!android_SetOutputVolume(opensles->stream, vol))
254 static UINT rdpsnd_opensles_play(rdpsndDevicePlugin* device,
const BYTE* data,
size_t size)
262 rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*)device;
263 DEBUG_SND(
"opensles=%p, data=%p, size=%d", (
void*)opensles, (
void*)data, size);
265 if (!rdpsnd_opensles_check_handle(opensles))
269 DEBUG_SND(
"size=%d, src=%p", size, (
void*)src.b);
270 WINPR_ASSERT(0 == size % 2);
271 WINPR_ASSERT(size > 0);
273 ret = android_AudioOut(opensles->stream, src.s, size / 2);
276 WLog_ERR(TAG,
"android_AudioOut failed (%d)", ret);
281 static void rdpsnd_opensles_start(rdpsndDevicePlugin* device)
283 rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*)device;
284 rdpsnd_opensles_check_handle(opensles);
285 DEBUG_SND(
"opensles=%p", (
void*)opensles);
288 static int rdpsnd_opensles_parse_addin_args(rdpsndDevicePlugin* device,
ADDIN_ARGV* args)
293 rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*)device;
295 {
"dev", COMMAND_LINE_VALUE_REQUIRED,
"<device>", NULL, NULL, -1, NULL,
"device" },
296 { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
299 WINPR_ASSERT(opensles);
301 DEBUG_SND(
"opensles=%p, args=%p", (
void*)opensles, (
void*)args);
303 COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
304 status = CommandLineParseArgumentsA(args->argc, args->argv, rdpsnd_opensles_args, flags,
305 opensles, NULL, NULL);
310 arg = rdpsnd_opensles_args;
314 if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
317 CommandLineSwitchStart(arg) CommandLineSwitchCase(arg,
"dev")
319 opensles->device_name = _strdup(arg->Value);
321 if (!opensles->device_name)
322 return ERROR_OUTOFMEMORY;
324 CommandLineSwitchEnd(arg)
325 }
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
335 FREERDP_ENTRY_POINT(UINT VCAPITYPE opensles_freerdp_rdpsnd_client_subsystem_entry(
339 rdpsndopenslesPlugin* opensles;
341 DEBUG_SND(
"pEntryPoints=%p", (
void*)pEntryPoints);
342 opensles = (rdpsndopenslesPlugin*)calloc(1,
sizeof(rdpsndopenslesPlugin));
345 return CHANNEL_RC_NO_MEMORY;
347 opensles->device.Open = rdpsnd_opensles_open;
348 opensles->device.FormatSupported = rdpsnd_opensles_format_supported;
349 opensles->device.GetVolume = rdpsnd_opensles_get_volume;
350 opensles->device.SetVolume = rdpsnd_opensles_set_volume;
351 opensles->device.Start = rdpsnd_opensles_start;
352 opensles->device.Play = rdpsnd_opensles_play;
353 opensles->device.Close = rdpsnd_opensles_close;
354 opensles->device.Free = rdpsnd_opensles_free;
355 args = pEntryPoints->args;
356 rdpsnd_opensles_parse_addin_args((rdpsndDevicePlugin*)opensles, args);
358 if (!opensles->device_name)
360 opensles->device_name = _strdup(
"default");
362 if (!opensles->device_name)
364 error = CHANNEL_RC_NO_MEMORY;
369 opensles->rate = 44100;
370 opensles->channels = 2;
371 opensles->format = WAVE_FORMAT_ADPCM;
372 pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)opensles);
373 DEBUG_SND(
"success");
374 return CHANNEL_RC_OK;