diff --git a/channels/rdpsnd/client/mac/rdpsnd_mac.c b/channels/rdpsnd/client/mac/rdpsnd_mac.c index c8e3bed84..2ed616866 100644 --- a/channels/rdpsnd/client/mac/rdpsnd_mac.c +++ b/channels/rdpsnd/client/mac/rdpsnd_mac.c @@ -17,10 +17,6 @@ * limitations under the License. */ -/** - * Use AudioQueue to implement audio redirection - */ - #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -40,163 +36,203 @@ #include "rdpsnd_main.h" -#define AQ_NUM_BUFFERS 10 -#define AQ_BUF_SIZE (32 * 1024) +#define AQ_NUM_BUFFERS 10 +#define AQ_BUF_SIZE (32 * 1024) -static void aq_playback_cb(void *user_data, - AudioQueueRef aq_ref, - AudioQueueBufferRef aq_buf_ref - ); - -struct rdpsnd_audio_q_plugin +struct rdpsnd_mac_plugin { rdpsndDevicePlugin device; - /* audio queue player state */ - int is_open; // true when audio_q has been inited - char * device_name; - int is_playing; - int buf_index; + BOOL isOpen; + BOOL isPlaying; + + UINT32 latency; + AUDIO_FORMAT format; + int audioBufferIndex; - AudioStreamBasicDescription data_format; - AudioQueueRef aq_ref; - AudioQueueBufferRef buffers[AQ_NUM_BUFFERS]; + AudioQueueRef audioQueue; + AudioStreamBasicDescription audioFormat; + AudioQueueBufferRef audioBuffers[AQ_NUM_BUFFERS]; }; -typedef struct rdpsnd_audio_q_plugin rdpsndAudioQPlugin; +typedef struct rdpsnd_mac_plugin rdpsndMacPlugin; -static void rdpsnd_audio_close(rdpsndDevicePlugin* device) +static void mac_audio_queue_output_cb(void* inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) { - rdpsndAudioQPlugin* aq_plugin_p = (rdpsndAudioQPlugin*) device; - - AudioQueueStop(aq_plugin_p->aq_ref, 0); - aq_plugin_p->is_open = 0; + } -static void rdpsnd_audio_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) -{ - int rv; - int i; - - rdpsndAudioQPlugin* aq_plugin_p = (rdpsndAudioQPlugin *) device; - if (aq_plugin_p->is_open) { - return; - } - - aq_plugin_p->buf_index = 0; - - // setup AudioStreamBasicDescription - aq_plugin_p->data_format.mSampleRate = 44100; - aq_plugin_p->data_format.mFormatID = kAudioFormatLinearPCM; - aq_plugin_p->data_format.mFormatFlags = kAudioFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; - - // until we know better, assume that one packet = one frame - // one frame = bytes_per_sample x number_of_channels - aq_plugin_p->data_format.mBytesPerPacket = 4; - aq_plugin_p->data_format.mFramesPerPacket = 1; - aq_plugin_p->data_format.mBytesPerFrame = 4; - aq_plugin_p->data_format.mChannelsPerFrame = 2; - aq_plugin_p->data_format.mBitsPerChannel = 16; - - rv = AudioQueueNewOutput( - &aq_plugin_p->data_format, // audio stream basic desc - aq_playback_cb, // callback when more data is required - aq_plugin_p, // data to pass to callback - CFRunLoopGetCurrent(), // The current run loop, and the one on - // which the audio queue playback callback - // will be invoked - kCFRunLoopCommonModes, // run loop modes in which callbacks can - // be invoked - 0, // flags - reserved - &aq_plugin_p->aq_ref - ); - if (rv != 0) { - fprintf(stderr, "rdpsnd_audio_open: AudioQueueNewOutput() failed with error %d\n", rv); - aq_plugin_p->is_open = 1; - return; - } - - for (i = 0; i < AQ_NUM_BUFFERS; i++) - { - rv = AudioQueueAllocateBuffer(aq_plugin_p->aq_ref, AQ_BUF_SIZE, &aq_plugin_p->buffers[i]); - } - - aq_plugin_p->is_open = 1; -} - -static void rdpsnd_audio_free(rdpsndDevicePlugin* device) -{ -} - -static BOOL rdpsnd_audio_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT* format) +static void rdpsnd_mac_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) { + rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; + + mac->latency = (UINT32) latency; + CopyMemory(&(mac->format), format, sizeof(AUDIO_FORMAT)); + switch (format->wFormatTag) { - case 1: /* PCM */ - if (format->cbSize == 0 && - (format->nSamplesPerSec <= 48000) && - (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && - (format->nChannels == 1 || format->nChannels == 2)) - { - return 1; - } - break; + case WAVE_FORMAT_ALAW: + mac->audioFormat.mFormatID = kAudioFormatALaw; + break; + + case WAVE_FORMAT_MULAW: + mac->audioFormat.mFormatID = kAudioFormatULaw; + break; + + case WAVE_FORMAT_PCM: + mac->audioFormat.mFormatID = kAudioFormatLinearPCM; + break; + + case WAVE_FORMAT_GSM610: + mac->audioFormat.mFormatID = kAudioFormatMicrosoftGSM; + break; + + default: + break; } - return 0; + + mac->audioFormat.mSampleRate = format->nSamplesPerSec; + mac->audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; + mac->audioFormat.mFramesPerPacket = 1; + mac->audioFormat.mChannelsPerFrame = format->nChannels; + mac->audioFormat.mBitsPerChannel = format->wBitsPerSample; + mac->audioFormat.mBytesPerFrame = (format->wBitsPerSample * format->nChannels) / 8; + mac->audioFormat.mBytesPerPacket = format->nBlockAlign; + + rdpsnd_print_audio_format(format); } -static void rdpsnd_audio_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) +static void rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) { -} - -static void rdpsnd_audio_set_volume(rdpsndDevicePlugin* device, UINT32 value) -{ -} - -static void rdpsnd_audio_play(rdpsndDevicePlugin* device, BYTE* data, int size) -{ - rdpsndAudioQPlugin* aq_plugin_p = (rdpsndAudioQPlugin *) device; - AudioQueueBufferRef aq_buf_ref; - int len; + int index; + OSStatus status; - if (!aq_plugin_p->is_open) { + rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; + + if (mac->isOpen) + return; + + mac->audioBufferIndex = 0; + + device->SetFormat(device, format, 0); + + status = AudioQueueNewOutput(&(mac->audioFormat), + mac_audio_queue_output_cb, mac, + NULL, NULL, 0, &(mac->audioQueue)); + + if (status != 0) + { + fprintf(stderr, "AudioQueueNewOutput failure\n"); return; } + + for (index = 0; index < AQ_NUM_BUFFERS; index++) + { + status = AudioQueueAllocateBuffer(mac->audioQueue, AQ_BUF_SIZE, &mac->audioBuffers[index]); + + if (status != 0) + { + fprintf(stderr, "AudioQueueAllocateBuffer failed\n"); + } + } + + mac->isOpen = TRUE; +} - /* get next empty buffer */ - aq_buf_ref = aq_plugin_p->buffers[aq_plugin_p->buf_index]; - - // fill aq_buf_ref with audio data - len = size > AQ_BUF_SIZE ? AQ_BUF_SIZE : size; - - memcpy(aq_buf_ref->mAudioData, (char *) data, len); - aq_buf_ref->mAudioDataByteSize = len; - - // add buffer to audioqueue - AudioQueueEnqueueBuffer(aq_plugin_p->aq_ref, aq_buf_ref, 0, 0); - - // update buf_index - aq_plugin_p->buf_index++; - if (aq_plugin_p->buf_index >= AQ_NUM_BUFFERS) { - aq_plugin_p->buf_index = 0; +static void rdpsnd_mac_close(rdpsndDevicePlugin* device) +{ + rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; + + if (mac->isOpen) + { + mac->isOpen = FALSE; + + AudioQueueStop(mac->audioQueue, true); + AudioQueueDispose(mac->audioQueue, true); + + mac->isPlaying = FALSE; } } -static void rdpsnd_audio_start(rdpsndDevicePlugin* device) +static void rdpsnd_mac_free(rdpsndDevicePlugin* device) { - rdpsndAudioQPlugin* aq_plugin_p = (rdpsndAudioQPlugin *) device; - - AudioQueueStart(aq_plugin_p->aq_ref, NULL); + } -/** - * AudioQueue Playback callback - * - * our job here is to fill aq_buf_ref with audio data and enqueue it - */ - -static void aq_playback_cb(void* user_data, AudioQueueRef aq_ref, AudioQueueBufferRef aq_buf_ref) +static BOOL rdpsnd_mac_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT* format) { + if (format->wFormatTag == WAVE_FORMAT_PCM) + { + return TRUE; + } + else if (format->wFormatTag == WAVE_FORMAT_ALAW) + { + return FALSE; + } + else if (format->wFormatTag == WAVE_FORMAT_MULAW) + { + return FALSE; + } + else if (format->wFormatTag == WAVE_FORMAT_GSM610) + { + return FALSE; + } + + return FALSE; +} +static void rdpsnd_mac_set_volume(rdpsndDevicePlugin* device, UINT32 value) +{ + +} + +static void rdpsnd_mac_start(rdpsndDevicePlugin* device) +{ + rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; + + if (!mac->isPlaying) + { + OSStatus status; + + if (!mac->audioQueue) + return; + + status = AudioQueueStart(mac->audioQueue, NULL); + + if (status != 0) + { + printf("AudioQueueStart failed\n"); + } + + mac->isPlaying = TRUE; + } +} + +static void rdpsnd_mac_play(rdpsndDevicePlugin* device, BYTE* data, int size) +{ + int length; + AudioQueueBufferRef audioBuffer; + rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; + + fprintf(stderr, "WavePlay\n"); + + if (!mac->isOpen) + return; + + audioBuffer = mac->audioBuffers[mac->audioBufferIndex]; + + length = size > AQ_BUF_SIZE ? AQ_BUF_SIZE : size; + + CopyMemory(audioBuffer->mAudioData, data, length); + audioBuffer->mAudioDataByteSize = length; + + AudioQueueEnqueueBuffer(mac->audioQueue, audioBuffer, 0, 0); + + mac->audioBufferIndex++; + + if (mac->audioBufferIndex >= AQ_NUM_BUFFERS) + mac->audioBufferIndex = 0; + + device->Start(device); } #ifdef STATIC_CHANNELS @@ -205,31 +241,25 @@ static void aq_playback_cb(void* user_data, AudioQueueRef aq_ref, AudioQueueBuff int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints) { - fprintf(stderr, "freerdp_rdpsnd_client_subsystem_entry()\n\n"); + rdpsndMacPlugin* mac; - ADDIN_ARGV* args; - rdpsndAudioQPlugin* aqPlugin; - - aqPlugin = (rdpsndAudioQPlugin*) malloc(sizeof(rdpsndAudioQPlugin)); - ZeroMemory(aqPlugin, sizeof(rdpsndAudioQPlugin)); - - aqPlugin->device.Open = rdpsnd_audio_open; - aqPlugin->device.FormatSupported = rdpsnd_audio_format_supported; - aqPlugin->device.SetFormat = rdpsnd_audio_set_format; - aqPlugin->device.SetVolume = rdpsnd_audio_set_volume; - aqPlugin->device.Play = rdpsnd_audio_play; - aqPlugin->device.Start = rdpsnd_audio_start; - aqPlugin->device.Close = rdpsnd_audio_close; - aqPlugin->device.Free = rdpsnd_audio_free; - - args = pEntryPoints->args; - - if (args->argc > 2) + mac = (rdpsndMacPlugin*) malloc(sizeof(rdpsndMacPlugin)); + + if (mac) { - /* TODO: parse device name */ - } + ZeroMemory(mac, sizeof(rdpsndMacPlugin)); + + mac->device.Open = rdpsnd_mac_open; + mac->device.FormatSupported = rdpsnd_mac_format_supported; + mac->device.SetFormat = rdpsnd_mac_set_format; + mac->device.SetVolume = rdpsnd_mac_set_volume; + mac->device.Play = rdpsnd_mac_play; + mac->device.Start = rdpsnd_mac_start; + mac->device.Close = rdpsnd_mac_close; + mac->device.Free = rdpsnd_mac_free; - pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) aqPlugin); + pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) mac); + } return 0; } diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index 1fc4c9e25..059db1637 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -718,7 +718,7 @@ static void rdpsnd_process_connect(rdpsndPlugin* rdpsnd) #if defined(WITH_MACAUDIO) if (!rdpsnd->device) { - rdpsnd_set_subsystem(rdpsnd, "macaudio"); + rdpsnd_set_subsystem(rdpsnd, "mac"); rdpsnd_set_device_name(rdpsnd, "default"); rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args); }