mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-15 08:54:38 +09:00
Merge pull request #2976 from akallabeth/mac_audin_support
Added audin support for mac os.
This commit is contained in:
@@ -52,3 +52,7 @@ endif()
|
||||
if(WITH_WINMM)
|
||||
add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "winmm" "")
|
||||
endif()
|
||||
|
||||
if(WITH_MACAUDIO)
|
||||
add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "mac" "")
|
||||
endif()
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* Copyright 2010-2011 Vic Lee
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||
* Copyright 2015 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -195,7 +196,7 @@ static UINT audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
Stream_Read_UINT16(s, format.cbSize);
|
||||
format.data = Stream_Pointer(s);
|
||||
Stream_Seek(s, format.cbSize);
|
||||
|
||||
|
||||
DEBUG_DVC("wFormatTag=%d nChannels=%d nSamplesPerSec=%d "
|
||||
"nBlockAlign=%d wBitsPerSample=%d cbSize=%d",
|
||||
format.wFormatTag, format.nChannels, format.nSamplesPerSec,
|
||||
@@ -310,7 +311,7 @@ static UINT audin_send_open_reply_pdu(IWTSVirtualChannelCallback* pChannelCallba
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT audin_receive_wave_data(BYTE* data, int size, void* user_data)
|
||||
static UINT audin_receive_wave_data(const BYTE* data, int size, void* user_data)
|
||||
{
|
||||
UINT error;
|
||||
wStream* out;
|
||||
@@ -667,7 +668,7 @@ static UINT audin_load_device_plugin(IWTSPlugin* pPlugin, const char* name, ADDI
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT audin_set_subsystem(AUDIN_PLUGIN* audin, char* subsystem)
|
||||
static UINT audin_set_subsystem(AUDIN_PLUGIN* audin, char* subsystem)
|
||||
{
|
||||
free(audin->subsystem);
|
||||
audin->subsystem = _strdup(subsystem);
|
||||
@@ -684,7 +685,7 @@ UINT audin_set_subsystem(AUDIN_PLUGIN* audin, char* subsystem)
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT audin_set_device_name(AUDIN_PLUGIN* audin, char* device_name)
|
||||
static UINT audin_set_device_name(AUDIN_PLUGIN* audin, char* device_name)
|
||||
{
|
||||
free(audin->device_name);
|
||||
audin->device_name = _strdup(device_name);
|
||||
@@ -696,7 +697,7 @@ UINT audin_set_device_name(AUDIN_PLUGIN* audin, char* device_name)
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
COMMAND_LINE_ARGUMENT_A audin_args[] =
|
||||
static COMMAND_LINE_ARGUMENT_A audin_args[] =
|
||||
{
|
||||
{ "sys", COMMAND_LINE_VALUE_REQUIRED, "<subsystem>", NULL, NULL, -1, NULL, "subsystem" },
|
||||
{ "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL, NULL, -1, NULL, "device" },
|
||||
@@ -779,9 +780,38 @@ static BOOL audin_process_addin_args(IWTSPlugin* pPlugin, ADDIN_ARGV* args)
|
||||
*/
|
||||
UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
{
|
||||
struct SubsystemEntry
|
||||
{
|
||||
char *subsystem;
|
||||
char *device;
|
||||
};
|
||||
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
ADDIN_ARGV* args;
|
||||
AUDIN_PLUGIN* audin;
|
||||
struct SubsystemEntry entries[] =
|
||||
{
|
||||
#if defined(WITH_PULSE)
|
||||
{"pulse", ""},
|
||||
#endif
|
||||
#if defined(WITH_OSS)
|
||||
{"oss", "default"},
|
||||
#endif
|
||||
#if defined(WITH_ALSA)
|
||||
{"alsa", "default"},
|
||||
#endif
|
||||
#if defined(WITH_OPENSLES)
|
||||
{"opensles", "default"},
|
||||
#endif
|
||||
#if defined(WITH_WINMM)
|
||||
{"winmm", "default"},
|
||||
#endif
|
||||
#if defined(WITH_MACAUDIO)
|
||||
{"mac", "default"},
|
||||
#endif
|
||||
{NULL,NULL}
|
||||
};
|
||||
struct SubsystemEntry *entry = &entries[0];
|
||||
|
||||
assert(pEntryPoints);
|
||||
assert(pEntryPoints->GetPlugin);
|
||||
@@ -807,123 +837,26 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
args = pEntryPoints->GetPluginData(pEntryPoints);
|
||||
audin->rdpcontext = ((freerdp*)((rdpSettings*) pEntryPoints->GetRdpSettings(pEntryPoints))->instance)->context;
|
||||
|
||||
if (error == CHANNEL_RC_OK)
|
||||
audin_process_addin_args((IWTSPlugin*) audin, args);
|
||||
else
|
||||
while (entry && entry->subsystem && !audin->device)
|
||||
{
|
||||
WLog_ERR(TAG, "RegisterPlugin failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_set_subsystem(audin, entry->subsystem)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_subsystem for %s failed with error %lu!",
|
||||
entry->subsystem, error);
|
||||
}
|
||||
else if ((error = audin_set_device_name(audin, entry->device)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_device_name for %s failed with error %lu!",
|
||||
entry->subsystem, error);
|
||||
}
|
||||
else if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_load_device_plugin %s failed with error %lu!",
|
||||
entry->subsystem, error);
|
||||
}
|
||||
|
||||
if (audin->subsystem && (error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args))) {
|
||||
WLog_ERR(TAG, "audin_load_device_plugin failed!");
|
||||
return error;
|
||||
}
|
||||
|
||||
#if defined(WITH_PULSE)
|
||||
if (!audin->device)
|
||||
{
|
||||
if ((error = audin_set_subsystem(audin, "pulse")))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_subsystem for pulse failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_set_device_name(audin, "")))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_device_name for pulse failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_load_device_plugin for pulse failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
entry++;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WITH_OSS)
|
||||
if (!audin->device)
|
||||
{
|
||||
if ((error = audin_set_subsystem(audin, "oss")))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_subsystem for oss failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_set_device_name(audin, "default")))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_device_name for oss failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_load_device_plugin oss pulse failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WITH_ALSA)
|
||||
if (!audin->device)
|
||||
{
|
||||
if ((error = audin_set_subsystem(audin, "alsa")))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_subsystem for alsa failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_set_device_name(audin, "default")))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_device_name for alsa failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_load_device_plugin oss alsa failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WITH_OPENSLES)
|
||||
if (!audin->device)
|
||||
{
|
||||
if ((error = audin_set_subsystem(audin, "opensles")))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_subsystem for opensles failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_set_device_name(audin, "default")))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_device_name for opensles failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_load_device_plugin oss opensles failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WITH_WINMM)
|
||||
if (!audin->device)
|
||||
{
|
||||
if ((error = audin_set_subsystem(audin, "winmm")))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_subsystem for winmm failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_set_device_name(audin, "default")))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_device_name for winmm failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_load_device_plugin oss winmm failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (audin->device == NULL)
|
||||
{
|
||||
|
||||
34
channels/audin/client/mac/CMakeLists.txt
Normal file
34
channels/audin/client/mac/CMakeLists.txt
Normal file
@@ -0,0 +1,34 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright (c) 2015 Armin Novak <armin.novak@thincast.com>
|
||||
# Copyright (c) 2015 Thincast Technologies GmbH
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
define_channel_client_subsystem("audin" "mac" "")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
audin_mac.c)
|
||||
|
||||
include_directories(..)
|
||||
include_directories(${MAC_INCLUDE_DIRS})
|
||||
|
||||
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
|
||||
|
||||
set(${MODULE_PREFIX}_LIBS freerdp ${MAC_LIBRARIES})
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
|
||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||
|
||||
461
channels/audin/client/mac/audin_mac.c
Normal file
461
channels/audin/client/mac/audin_mac.c
Normal file
@@ -0,0 +1,461 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Audio Input Redirection Virtual Channel - Mac OS X implementation
|
||||
*
|
||||
* Copyright (c) 2015 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/string.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/debug.h>
|
||||
#include <winpr/cmdline.h>
|
||||
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#include <CoreAudio/CoreAudio.h>
|
||||
#include <AudioToolbox/AudioToolbox.h>
|
||||
#include <AudioToolbox/AudioQueue.h>
|
||||
|
||||
#include <freerdp/addin.h>
|
||||
#include <freerdp/codec/dsp.h>
|
||||
#include <freerdp/channels/rdpsnd.h>
|
||||
|
||||
#include "audin_main.h"
|
||||
|
||||
#define MAC_AUDIO_QUEUE_NUM_BUFFERS 100
|
||||
#define MAC_AUDIO_QUEUE_BUFFER_SIZE 32768
|
||||
|
||||
typedef struct _AudinMacDevice
|
||||
{
|
||||
IAudinDevice iface;
|
||||
|
||||
FREERDP_DSP_CONTEXT* dsp_context;
|
||||
|
||||
audinFormat format;
|
||||
UINT32 FramesPerPacket;
|
||||
int dev_unit;
|
||||
|
||||
AudinReceive receive;
|
||||
void* user_data;
|
||||
|
||||
rdpContext* rdpcontext;
|
||||
|
||||
bool isOpen;
|
||||
AudioQueueRef audioQueue;
|
||||
AudioStreamBasicDescription audioFormat;
|
||||
AudioQueueBufferRef audioBuffers[MAC_AUDIO_QUEUE_NUM_BUFFERS];
|
||||
} AudinMacDevice;
|
||||
|
||||
static AudioFormatID audin_mac_get_format(const audinFormat* format)
|
||||
{
|
||||
switch (format->wFormatTag)
|
||||
{
|
||||
case WAVE_FORMAT_PCM:
|
||||
return kAudioFormatLinearPCM;
|
||||
/*
|
||||
case WAVE_FORMAT_GSM610:
|
||||
return kAudioFormatMicrosoftGSM;
|
||||
case WAVE_FORMAT_ALAW:
|
||||
return kAudioFormatALaw;
|
||||
case WAVE_FORMAT_MULAW:
|
||||
return kAudioFormatULaw;
|
||||
case WAVE_FORMAT_AAC_MS:
|
||||
return kAudioFormatMPEG4AAC;
|
||||
case WAVE_FORMAT_ADPCM:
|
||||
case WAVE_FORMAT_DVI_ADPCM:
|
||||
return kAudioFormatLinearPCM;
|
||||
*/
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static AudioFormatFlags audin_mac_get_flags_for_format(const audinFormat* format)
|
||||
{
|
||||
switch(format->wFormatTag)
|
||||
{
|
||||
case WAVE_FORMAT_DVI_ADPCM:
|
||||
case WAVE_FORMAT_ADPCM:
|
||||
case WAVE_FORMAT_PCM:
|
||||
return kAudioFormatFlagIsSignedInteger;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL audin_mac_format_supported(IAudinDevice* device, audinFormat* format)
|
||||
{
|
||||
AudioFormatID req_fmt = 0;
|
||||
|
||||
if (device == NULL || format == NULL)
|
||||
return FALSE;
|
||||
|
||||
req_fmt = audin_mac_get_format(format);
|
||||
|
||||
if (req_fmt == 0)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT audin_mac_set_format(IAudinDevice* device, audinFormat* format, UINT32 FramesPerPacket)
|
||||
{
|
||||
AudinMacDevice* mac = (AudinMacDevice*)device;
|
||||
|
||||
if (device == NULL || format == NULL)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
mac->FramesPerPacket = FramesPerPacket;
|
||||
CopyMemory(&(mac->format), format, sizeof(audinFormat));
|
||||
|
||||
WLog_INFO(TAG, "Audio Format %s [channels=%d, samples=%d, bits=%d]",
|
||||
rdpsnd_get_audio_tag_string(format->wFormatTag),
|
||||
format->nChannels, format->nSamplesPerSec, format->wBitsPerSample);
|
||||
|
||||
switch (format->wFormatTag)
|
||||
{
|
||||
case WAVE_FORMAT_ADPCM:
|
||||
case WAVE_FORMAT_DVI_ADPCM:
|
||||
mac->FramesPerPacket *= 4; /* Compression ratio. */
|
||||
mac->format.wBitsPerSample *= 4;
|
||||
break;
|
||||
}
|
||||
|
||||
mac->audioFormat.mBitsPerChannel = mac->format.wBitsPerSample;
|
||||
mac->audioFormat.mChannelsPerFrame = mac->format.nChannels;
|
||||
mac->audioFormat.mFormatFlags = audin_mac_get_flags_for_format(format);
|
||||
mac->audioFormat.mFormatID = audin_mac_get_format(format);
|
||||
mac->audioFormat.mFramesPerPacket = 1;
|
||||
mac->audioFormat.mSampleRate = mac->format.nSamplesPerSec;
|
||||
mac->audioFormat.mBytesPerFrame =
|
||||
mac->audioFormat.mChannelsPerFrame * mac->audioFormat.mBitsPerChannel / 8;
|
||||
mac->audioFormat.mBytesPerPacket =
|
||||
mac->audioFormat.mBytesPerFrame * mac->audioFormat.mFramesPerPacket;
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void mac_audio_queue_input_cb(void *aqData,
|
||||
AudioQueueRef inAQ,
|
||||
AudioQueueBufferRef inBuffer,
|
||||
const AudioTimeStamp *inStartTime,
|
||||
UInt32 inNumPackets,
|
||||
const AudioStreamPacketDescription *inPacketDesc)
|
||||
{
|
||||
AudinMacDevice* mac = (AudinMacDevice*)aqData;
|
||||
UINT error;
|
||||
int encoded_size;
|
||||
const BYTE *encoded_data;
|
||||
BYTE *buffer = inBuffer->mAudioData;
|
||||
int buffer_size = inBuffer->mAudioDataByteSize;
|
||||
|
||||
(void)inAQ;
|
||||
(void)inStartTime;
|
||||
(void)inNumPackets;
|
||||
(void)inPacketDesc;
|
||||
|
||||
|
||||
/* Process. */
|
||||
switch (mac->format.wFormatTag) {
|
||||
case WAVE_FORMAT_ADPCM:
|
||||
if (!mac->dsp_context->encode_ms_adpcm(mac->dsp_context,
|
||||
buffer, buffer_size, mac->format.nChannels, mac->format.nBlockAlign))
|
||||
{
|
||||
SetLastError(ERROR_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
encoded_data = mac->dsp_context->adpcm_buffer;
|
||||
encoded_size = mac->dsp_context->adpcm_size;
|
||||
break;
|
||||
case WAVE_FORMAT_DVI_ADPCM:
|
||||
if (!mac->dsp_context->encode_ima_adpcm(mac->dsp_context,
|
||||
buffer, buffer_size, mac->format.nChannels, mac->format.nBlockAlign))
|
||||
{
|
||||
SetLastError(ERROR_INTERNAL_ERROR);
|
||||
break;
|
||||
}
|
||||
encoded_data = mac->dsp_context->adpcm_buffer;
|
||||
encoded_size = mac->dsp_context->adpcm_size;
|
||||
break;
|
||||
default:
|
||||
encoded_data = buffer;
|
||||
encoded_size = buffer_size;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((error = mac->receive(encoded_data, encoded_size, mac->user_data)))
|
||||
{
|
||||
WLog_ERR(TAG, "mac->receive failed with error %lu", error);
|
||||
SetLastError(ERROR_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static UINT audin_mac_close(IAudinDevice *device)
|
||||
{
|
||||
UINT errCode = CHANNEL_RC_OK;
|
||||
char errString[1024];
|
||||
OSStatus devStat;
|
||||
AudinMacDevice *mac = (AudinMacDevice*)device;
|
||||
|
||||
if (device == NULL)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (mac->isOpen)
|
||||
{
|
||||
devStat = AudioQueueStop(mac->audioQueue, true);
|
||||
if (devStat != 0)
|
||||
{
|
||||
errCode = GetLastError();
|
||||
WLog_ERR(TAG, "AudioQueueStop failed with %s [%d]",
|
||||
winpr_strerror(errCode, errString, sizeof(errString)), errCode);
|
||||
}
|
||||
mac->isOpen = false;
|
||||
}
|
||||
|
||||
if (mac->audioQueue)
|
||||
{
|
||||
devStat = AudioQueueDispose(mac->audioQueue, true);
|
||||
if (devStat != 0)
|
||||
{
|
||||
errCode = GetLastError();
|
||||
WLog_ERR(TAG, "AudioQueueDispose failed with %s [%d]",
|
||||
winpr_strerror(errCode, errString, sizeof(errString)), errCode);
|
||||
}
|
||||
|
||||
mac->audioQueue = NULL;
|
||||
}
|
||||
|
||||
mac->receive = NULL;
|
||||
mac->user_data = NULL;
|
||||
|
||||
return errCode;
|
||||
}
|
||||
|
||||
static UINT audin_mac_open(IAudinDevice *device, AudinReceive receive, void *user_data) {
|
||||
AudinMacDevice *mac = (AudinMacDevice*)device;
|
||||
DWORD errCode;
|
||||
char errString[1024];
|
||||
OSStatus devStat;
|
||||
size_t index;
|
||||
|
||||
mac->receive = receive;
|
||||
mac->user_data = user_data;
|
||||
|
||||
devStat = AudioQueueNewInput(&(mac->audioFormat), mac_audio_queue_input_cb,
|
||||
mac, NULL, kCFRunLoopCommonModes, 0, &(mac->audioQueue));
|
||||
if (devStat != 0)
|
||||
{
|
||||
errCode = GetLastError();
|
||||
WLog_ERR(TAG, "AudioQueueNewInput failed with %s [%d]",
|
||||
winpr_strerror(errCode, errString, sizeof(errString)), errCode);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
for (index = 0; index < MAC_AUDIO_QUEUE_NUM_BUFFERS; index++)
|
||||
{
|
||||
devStat = AudioQueueAllocateBuffer(mac->audioQueue, MAC_AUDIO_QUEUE_BUFFER_SIZE,
|
||||
&mac->audioBuffers[index]);
|
||||
if (devStat != 0)
|
||||
{
|
||||
errCode = GetLastError();
|
||||
WLog_ERR(TAG, "AudioQueueAllocateBuffer failed with %s [%d]",
|
||||
winpr_strerror(errCode, errString, sizeof(errString)), errCode);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
devStat = AudioQueueEnqueueBuffer(mac->audioQueue,
|
||||
mac->audioBuffers[index],
|
||||
0,
|
||||
NULL);
|
||||
if (devStat != 0)
|
||||
{
|
||||
errCode = GetLastError();
|
||||
WLog_ERR(TAG, "AudioQueueEnqueueBuffer failed with %s [%d]",
|
||||
winpr_strerror(errCode, errString, sizeof(errString)), errCode);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
freerdp_dsp_context_reset_adpcm(mac->dsp_context);
|
||||
|
||||
devStat = AudioQueueStart(mac->audioQueue, NULL);
|
||||
if (devStat != 0)
|
||||
{
|
||||
errCode = GetLastError();
|
||||
WLog_ERR(TAG, "AudioQueueStart failed with %s [%d]",
|
||||
winpr_strerror(errCode, errString, sizeof(errString)), errCode);
|
||||
goto err_out;
|
||||
}
|
||||
mac->isOpen = true;
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
err_out:
|
||||
audin_mac_close(device);
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR;
|
||||
}
|
||||
|
||||
static UINT audin_mac_free(IAudinDevice* device)
|
||||
{
|
||||
AudinMacDevice *mac = (AudinMacDevice*)device;
|
||||
|
||||
int error;
|
||||
|
||||
if (device == NULL)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if ((error = audin_mac_close(device)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_oss_close failed with error code %d!", error);
|
||||
}
|
||||
freerdp_dsp_context_free(mac->dsp_context);
|
||||
free(mac);
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static COMMAND_LINE_ARGUMENT_A audin_mac_args[] =
|
||||
{
|
||||
{ "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL, NULL, -1, NULL, "audio device name" },
|
||||
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
|
||||
};
|
||||
|
||||
static UINT audin_mac_parse_addin_args(AudinMacDevice *device, ADDIN_ARGV *args)
|
||||
{
|
||||
DWORD errCode;
|
||||
char errString[1024];
|
||||
int status;
|
||||
char* str_num, *eptr;
|
||||
DWORD flags;
|
||||
COMMAND_LINE_ARGUMENT_A* arg;
|
||||
AudinMacDevice* mac = (AudinMacDevice*)device;
|
||||
|
||||
if (args->argc == 1)
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
|
||||
status = CommandLineParseArgumentsA(args->argc, (const char**)args->argv, audin_mac_args, flags, mac, NULL, NULL);
|
||||
|
||||
if (status < 0)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
arg = audin_mac_args;
|
||||
|
||||
do
|
||||
{
|
||||
if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
|
||||
continue;
|
||||
|
||||
CommandLineSwitchStart(arg)
|
||||
CommandLineSwitchCase(arg, "dev")
|
||||
{
|
||||
str_num = _strdup(arg->Value);
|
||||
if (!str_num)
|
||||
{
|
||||
errCode = GetLastError();
|
||||
WLog_ERR(TAG, "_strdup failed with %s [%d]",
|
||||
winpr_strerror(errCode, errString, sizeof(errString)), errCode);
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
mac->dev_unit = strtol(str_num, &eptr, 10);
|
||||
|
||||
if (mac->dev_unit < 0 || *eptr != '\0')
|
||||
mac->dev_unit = -1;
|
||||
|
||||
free(str_num);
|
||||
}
|
||||
CommandLineSwitchEnd(arg)
|
||||
}
|
||||
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
#ifdef STATIC_CHANNELS
|
||||
#define freerdp_audin_client_subsystem_entry mac_freerdp_audin_client_subsystem_entry
|
||||
#endif
|
||||
|
||||
UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
|
||||
{
|
||||
DWORD errCode;
|
||||
char errString[1024];
|
||||
ADDIN_ARGV *args;
|
||||
AudinMacDevice *mac;
|
||||
UINT error;
|
||||
|
||||
mac = (AudinMacDevice*)calloc(1, sizeof(AudinMacDevice));
|
||||
if (!mac)
|
||||
{
|
||||
errCode = GetLastError();
|
||||
WLog_ERR(TAG, "calloc failed with %s [%d]",
|
||||
winpr_strerror(errCode, errString, sizeof(errString)), errCode);
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
mac->iface.Open = audin_mac_open;
|
||||
mac->iface.FormatSupported = audin_mac_format_supported;
|
||||
mac->iface.SetFormat = audin_mac_set_format;
|
||||
mac->iface.Close = audin_mac_close;
|
||||
mac->iface.Free = audin_mac_free;
|
||||
mac->rdpcontext = pEntryPoints->rdpcontext;
|
||||
|
||||
mac->dev_unit = -1;
|
||||
args = pEntryPoints->args;
|
||||
|
||||
if ((error = audin_mac_parse_addin_args(mac, args)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_mac_parse_addin_args failed with %lu!", error);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
mac->dsp_context = freerdp_dsp_context_new();
|
||||
if (!mac->dsp_context)
|
||||
{
|
||||
WLog_ERR(TAG, "freerdp_dsp_context_new failed!");
|
||||
error = CHANNEL_RC_NO_MEMORY;
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) mac)))
|
||||
{
|
||||
WLog_ERR(TAG, "RegisterAudinDevice failed with error %lu!", error);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
error_out:
|
||||
freerdp_dsp_context_free(mac->dsp_context);
|
||||
free(mac);
|
||||
return error;
|
||||
|
||||
}
|
||||
@@ -29,7 +29,7 @@
|
||||
* Subsystem Interface
|
||||
*/
|
||||
|
||||
typedef UINT (*AudinReceive) (BYTE* data, int size, void* userData);
|
||||
typedef UINT (*AudinReceive) (const BYTE* data, int size, void* userData);
|
||||
|
||||
typedef struct audin_format audinFormat;
|
||||
struct audin_format
|
||||
|
||||
@@ -181,6 +181,7 @@ typedef struct AUDIO_FORMAT AUDIO_FORMAT;
|
||||
#define WAVE_FORMAT_NORRIS 0x1400
|
||||
#define WAVE_FORMAT_SOUNDSPACE_MUSICOMPRESS 0x1500
|
||||
#define WAVE_FORMAT_DVM 0x2000
|
||||
#define WAVE_FORMAT_AAC_MS 0xA106
|
||||
|
||||
/**
|
||||
* Audio Format Functions
|
||||
|
||||
@@ -105,6 +105,9 @@ char* rdpsnd_get_audio_tag_string(UINT16 wFormatTag)
|
||||
|
||||
case WAVE_FORMAT_WMAUDIO2:
|
||||
return "WAVE_FORMAT_WMAUDIO2";
|
||||
|
||||
case WAVE_FORMAT_AAC_MS:
|
||||
return "WAVE_FORMAT_AAC_MS";
|
||||
}
|
||||
|
||||
return "WAVE_FORMAT_UNKNOWN";
|
||||
|
||||
Reference in New Issue
Block a user