22#include <freerdp/config.h> 
   24#include <winpr/wtypes.h> 
   26#include <freerdp/types.h> 
   27#include <freerdp/codec/dsp.h> 
   29#import <AudioToolbox/AudioToolbox.h> 
   31#include "rdpsnd_main.h" 
   32#include "TPCircularBuffer.h" 
   34#define INPUT_BUFFER_SIZE 32768 
   35#define CIRCULAR_BUFFER_SIZE (INPUT_BUFFER_SIZE * 4) 
   39  rdpsndDevicePlugin device;
 
   40  AudioComponentInstance audio_unit;
 
   46#define THIS(__ptr) ((rdpsndIOSPlugin*)__ptr) 
   48static OSStatus rdpsnd_ios_render_cb(
void* inRefCon,
 
   49                                     AudioUnitRenderActionFlags __unused* ioActionFlags,
 
   50                                     const AudioTimeStamp __unused* inTimeStamp, UInt32 inBusNumber,
 
   51                                     UInt32 __unused inNumberFrames, AudioBufferList* ioData)
 
   58  rdpsndIOSPlugin* p = THIS(inRefCon);
 
   60  for (
unsigned int i = 0; i < ioData->mNumberBuffers; i++)
 
   62    AudioBuffer* target_buffer = &ioData->mBuffers[i];
 
   63    int32_t available_bytes = 0;
 
   64    const void* buffer = TPCircularBufferTail(&p->buffer, &available_bytes);
 
   66    if (buffer != NULL && available_bytes > 0)
 
   68      const int bytes_to_copy = MIN((int32_t)target_buffer->mDataByteSize, available_bytes);
 
   69      memcpy(target_buffer->mData, buffer, bytes_to_copy);
 
   70      target_buffer->mDataByteSize = bytes_to_copy;
 
   71      TPCircularBufferConsume(&p->buffer, bytes_to_copy);
 
   75      target_buffer->mDataByteSize = 0;
 
   76      AudioOutputUnitStop(p->audio_unit);
 
   84static BOOL rdpsnd_ios_format_supported(rdpsndDevicePlugin* __unused device,
 
   87  if (format->wFormatTag == WAVE_FORMAT_PCM)
 
   95static BOOL rdpsnd_ios_set_volume(rdpsndDevicePlugin* __unused device, UINT32 __unused value)
 
  100static void rdpsnd_ios_start(rdpsndDevicePlugin* device)
 
  102  rdpsndIOSPlugin* p = THIS(device);
 
  108    int32_t available_bytes = 0;
 
  109    TPCircularBufferTail(&p->buffer, &available_bytes);
 
  111    if (available_bytes > 0)
 
  114      AudioOutputUnitStart(p->audio_unit);
 
  119static void rdpsnd_ios_stop(rdpsndDevicePlugin* __unused device)
 
  121  rdpsndIOSPlugin* p = THIS(device);
 
  127    AudioOutputUnitStop(p->audio_unit);
 
  130    TPCircularBufferClear(&p->buffer);
 
  134static UINT rdpsnd_ios_play(rdpsndDevicePlugin* device, 
const BYTE* data, 
size_t size)
 
  136  rdpsndIOSPlugin* p = THIS(device);
 
  137  const BOOL ok = TPCircularBufferProduceBytes(&p->buffer, data, size);
 
  142  rdpsnd_ios_start(device);
 
  146static BOOL rdpsnd_ios_open(rdpsndDevicePlugin* device, 
const AUDIO_FORMAT* format,
 
  147                            UINT32 __unused latency)
 
  149  rdpsndIOSPlugin* p = THIS(device);
 
  155  AudioComponentDescription desc;
 
  156  desc.componentManufacturer = kAudioUnitManufacturer_Apple;
 
  157  desc.componentType = kAudioUnitType_Output;
 
  158  desc.componentSubType = kAudioUnitSubType_RemoteIO;
 
  159  desc.componentFlags = 0;
 
  160  desc.componentFlagsMask = 0;
 
  161  AudioComponent audioComponent = AudioComponentFindNext(NULL, &desc);
 
  163  if (audioComponent == NULL)
 
  167  OSStatus status = AudioComponentInstanceNew(audioComponent, &p->audio_unit);
 
  173  AudioStreamBasicDescription audioFormat = { 0 };
 
  174  audioFormat.mSampleRate = format->nSamplesPerSec;
 
  175  audioFormat.mFormatID = kAudioFormatLinearPCM;
 
  176  audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
 
  177  audioFormat.mFramesPerPacket = 1; 
 
  178  audioFormat.mChannelsPerFrame = format->nChannels;
 
  179  audioFormat.mBitsPerChannel = format->wBitsPerSample;
 
  180  audioFormat.mBytesPerFrame = (format->wBitsPerSample * format->nChannels) / 8;
 
  181  audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame * audioFormat.mFramesPerPacket;
 
  182  status = AudioUnitSetProperty(p->audio_unit, kAudioUnitProperty_StreamFormat,
 
  183                                kAudioUnitScope_Input, 0, &audioFormat, 
sizeof(audioFormat));
 
  187    AudioComponentInstanceDispose(p->audio_unit);
 
  188    p->audio_unit = NULL;
 
  193  AURenderCallbackStruct callbackStruct = { 0 };
 
  194  callbackStruct.inputProc = rdpsnd_ios_render_cb;
 
  195  callbackStruct.inputProcRefCon = p;
 
  197      AudioUnitSetProperty(p->audio_unit, kAudioUnitProperty_SetRenderCallback,
 
  198                           kAudioUnitScope_Input, 0, &callbackStruct, 
sizeof(callbackStruct));
 
  202    AudioComponentInstanceDispose(p->audio_unit);
 
  203    p->audio_unit = NULL;
 
  208  status = AudioUnitInitialize(p->audio_unit);
 
  212    AudioComponentInstanceDispose(p->audio_unit);
 
  213    p->audio_unit = NULL;
 
  218  const BOOL ok = TPCircularBufferInit(&p->buffer, CIRCULAR_BUFFER_SIZE);
 
  222    AudioUnitUninitialize(p->audio_unit);
 
  223    AudioComponentInstanceDispose(p->audio_unit);
 
  224    p->audio_unit = NULL;
 
  232static void rdpsnd_ios_close(rdpsndDevicePlugin* device)
 
  234  rdpsndIOSPlugin* p = THIS(device);
 
  236  rdpsnd_ios_stop(device);
 
  242    AudioUnitUninitialize(p->audio_unit);
 
  243    AudioComponentInstanceDispose(p->audio_unit);
 
  244    p->audio_unit = NULL;
 
  247    TPCircularBufferCleanup(&p->buffer);
 
  251static void rdpsnd_ios_free(rdpsndDevicePlugin* device)
 
  253  rdpsndIOSPlugin* p = THIS(device);
 
  255  rdpsnd_ios_close(device);
 
  265FREERDP_ENTRY_POINT(UINT VCAPITYPE ios_freerdp_rdpsnd_client_subsystem_entry(
 
  268  rdpsndIOSPlugin* p = (rdpsndIOSPlugin*)calloc(1, 
sizeof(rdpsndIOSPlugin));
 
  271    return CHANNEL_RC_NO_MEMORY;
 
  273  p->device.Open = rdpsnd_ios_open;
 
  274  p->device.FormatSupported = rdpsnd_ios_format_supported;
 
  275  p->device.SetVolume = rdpsnd_ios_set_volume;
 
  276  p->device.Play = rdpsnd_ios_play;
 
  277  p->device.Start = rdpsnd_ios_start;
 
  278  p->device.Close = rdpsnd_ios_close;
 
  279  p->device.Free = rdpsnd_ios_free;
 
  280  pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)p);
 
  281  return CHANNEL_RC_OK;