21 #include <freerdp/config.h>
27 #include <winpr/crt.h>
28 #include <winpr/synch.h>
29 #include <winpr/string.h>
30 #include <winpr/thread.h>
31 #include <winpr/debug.h>
32 #include <winpr/cmdline.h>
34 #import <AVFoundation/AVFoundation.h>
36 #define __COREFOUNDATION_CFPLUGINCOM__ 1
37 #define IUNKNOWN_C_GUTS \
39 void *QueryInterface; \
43 #include <CoreAudio/CoreAudioTypes.h>
44 #include <AudioToolbox/AudioToolbox.h>
45 #include <AudioToolbox/AudioQueue.h>
47 #include <freerdp/addin.h>
48 #include <freerdp/channels/rdpsnd.h>
50 #include "audin_main.h"
52 #define IOS_AUDIO_QUEUE_NUM_BUFFERS 100
59 UINT32 FramesPerPacket;
65 rdpContext *rdpcontext;
68 AudioQueueRef audioQueue;
69 AudioStreamBasicDescription audioFormat;
70 AudioQueueBufferRef audioBuffers[IOS_AUDIO_QUEUE_NUM_BUFFERS];
73 static AudioFormatID audin_ios_get_format(
const AUDIO_FORMAT *format)
75 switch (format->wFormatTag)
78 return kAudioFormatLinearPCM;
85 static AudioFormatFlags audin_ios_get_flags_for_format(
const AUDIO_FORMAT *format)
87 switch (format->wFormatTag)
90 return kAudioFormatFlagIsSignedInteger;
97 static BOOL audin_ios_format_supported(IAudinDevice *device,
const AUDIO_FORMAT *format)
99 AudinIosDevice *ios = (AudinIosDevice *)device;
100 AudioFormatID req_fmt = 0;
102 if (device == NULL || format == NULL)
105 req_fmt = audin_ios_get_format(format);
118 static UINT audin_ios_set_format(IAudinDevice *device,
const AUDIO_FORMAT *format,
119 UINT32 FramesPerPacket)
121 AudinIosDevice *ios = (AudinIosDevice *)device;
123 if (device == NULL || format == NULL)
124 return ERROR_INVALID_PARAMETER;
126 ios->FramesPerPacket = FramesPerPacket;
127 ios->format = *format;
128 WLog_INFO(TAG,
"Audio Format %s [channels=%d, samples=%d, bits=%d]",
129 audio_format_get_tag_string(format->wFormatTag), format->nChannels,
130 format->nSamplesPerSec, format->wBitsPerSample);
131 ios->audioFormat.mBitsPerChannel = format->wBitsPerSample;
133 if (format->wBitsPerSample == 0)
134 ios->audioFormat.mBitsPerChannel = 16;
136 ios->audioFormat.mChannelsPerFrame = ios->format.nChannels;
137 ios->audioFormat.mFramesPerPacket = 1;
139 ios->audioFormat.mBytesPerFrame =
140 ios->audioFormat.mChannelsPerFrame * (ios->audioFormat.mBitsPerChannel / 8);
141 ios->audioFormat.mBytesPerPacket =
142 ios->audioFormat.mBytesPerFrame * ios->audioFormat.mFramesPerPacket;
144 ios->audioFormat.mFormatFlags = audin_ios_get_flags_for_format(format);
145 ios->audioFormat.mFormatID = audin_ios_get_format(format);
146 ios->audioFormat.mReserved = 0;
147 ios->audioFormat.mSampleRate = ios->format.nSamplesPerSec;
148 return CHANNEL_RC_OK;
151 static void ios_audio_queue_input_cb(
void *aqData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer,
152 const AudioTimeStamp *inStartTime, UInt32 inNumPackets,
153 const AudioStreamPacketDescription *inPacketDesc)
155 AudinIosDevice *ios = (AudinIosDevice *)aqData;
156 UINT error = CHANNEL_RC_OK;
157 const BYTE *buffer = inBuffer->mAudioData;
158 int buffer_size = inBuffer->mAudioDataByteSize;
165 error = ios->receive(&ios->format, buffer, buffer_size, ios->user_data);
167 AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL);
171 WLog_ERR(TAG,
"ios->receive failed with error %" PRIu32
"", error);
172 SetLastError(ERROR_INTERNAL_ERROR);
176 static UINT audin_ios_close(IAudinDevice *device)
178 UINT errCode = CHANNEL_RC_OK;
179 char errString[1024];
181 AudinIosDevice *ios = (AudinIosDevice *)device;
184 return ERROR_INVALID_PARAMETER;
188 devStat = AudioQueueStop(ios->audioQueue,
true);
192 errCode = GetLastError();
193 WLog_ERR(TAG,
"AudioQueueStop failed with %s [%" PRIu32
"]",
194 winpr_strerror(errCode, errString,
sizeof(errString)), errCode);
202 devStat = AudioQueueDispose(ios->audioQueue,
true);
206 errCode = GetLastError();
207 WLog_ERR(TAG,
"AudioQueueDispose failed with %s [%" PRIu32
"]",
208 winpr_strerror(errCode, errString,
sizeof(errString)), errCode);
211 ios->audioQueue = NULL;
215 ios->user_data = NULL;
219 static UINT audin_ios_open(IAudinDevice *device, AudinReceive receive,
void *user_data)
221 AudinIosDevice *ios = (AudinIosDevice *)device;
223 char errString[1024];
226 ios->receive = receive;
227 ios->user_data = user_data;
228 devStat = AudioQueueNewInput(&(ios->audioFormat), ios_audio_queue_input_cb, ios, NULL,
229 kCFRunLoopCommonModes, 0, &(ios->audioQueue));
233 errCode = GetLastError();
234 WLog_ERR(TAG,
"AudioQueueNewInput failed with %s [%" PRIu32
"]",
235 winpr_strerror(errCode, errString,
sizeof(errString)), errCode);
239 for (
size_t index = 0; index < IOS_AUDIO_QUEUE_NUM_BUFFERS; index++)
241 devStat = AudioQueueAllocateBuffer(ios->audioQueue,
242 ios->FramesPerPacket * 2 * ios->format.nChannels,
243 &ios->audioBuffers[index]);
247 errCode = GetLastError();
248 WLog_ERR(TAG,
"AudioQueueAllocateBuffer failed with %s [%" PRIu32
"]",
249 winpr_strerror(errCode, errString,
sizeof(errString)), errCode);
253 devStat = AudioQueueEnqueueBuffer(ios->audioQueue, ios->audioBuffers[index], 0, NULL);
257 errCode = GetLastError();
258 WLog_ERR(TAG,
"AudioQueueEnqueueBuffer failed with %s [%" PRIu32
"]",
259 winpr_strerror(errCode, errString,
sizeof(errString)), errCode);
264 devStat = AudioQueueStart(ios->audioQueue, NULL);
268 errCode = GetLastError();
269 WLog_ERR(TAG,
"AudioQueueStart failed with %s [%" PRIu32
"]",
270 winpr_strerror(errCode, errString,
sizeof(errString)), errCode);
275 return CHANNEL_RC_OK;
277 audin_ios_close(device);
278 return CHANNEL_RC_INITIALIZATION_ERROR;
281 static UINT audin_ios_free(IAudinDevice *device)
283 AudinIosDevice *ios = (AudinIosDevice *)device;
287 return ERROR_INVALID_PARAMETER;
289 if ((error = audin_ios_close(device)))
291 WLog_ERR(TAG,
"audin_oss_close failed with error code %d!", error);
295 return CHANNEL_RC_OK;
298 FREERDP_ENTRY_POINT(UINT VCAPITYPE ios_freerdp_audin_client_subsystem_entry(
302 char errString[1024];
306 ios = (AudinIosDevice *)calloc(1,
sizeof(AudinIosDevice));
310 errCode = GetLastError();
311 WLog_ERR(TAG,
"calloc failed with %s [%" PRIu32
"]",
312 winpr_strerror(errCode, errString,
sizeof(errString)), errCode);
313 return CHANNEL_RC_NO_MEMORY;
316 ios->iface.Open = audin_ios_open;
317 ios->iface.FormatSupported = audin_ios_format_supported;
318 ios->iface.SetFormat = audin_ios_set_format;
319 ios->iface.Close = audin_ios_close;
320 ios->iface.Free = audin_ios_free;
321 ios->rdpcontext = pEntryPoints->rdpcontext;
323 args = pEntryPoints->args;
325 if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice *)ios)))
327 WLog_ERR(TAG,
"RegisterAudinDevice failed with error %" PRIu32
"!", error);
331 return CHANNEL_RC_OK;