Added permission checks for mac audio backend.

This commit is contained in:
Armin Novak 2020-10-19 12:08:13 +02:00 committed by akallabeth
parent e18597f5eb
commit 0e0eb5f41f
4 changed files with 85 additions and 31 deletions

View File

@ -18,17 +18,18 @@
define_channel_client_subsystem("audin" "mac" "") define_channel_client_subsystem("audin" "mac" "")
FIND_LIBRARY(CORE_AUDIO CoreAudio) FIND_LIBRARY(CORE_AUDIO CoreAudio)
FIND_LIBRARY(AVFOUNDATION AVFoundation)
FIND_LIBRARY(AUDIO_TOOL AudioToolbox) FIND_LIBRARY(AUDIO_TOOL AudioToolbox)
FIND_LIBRARY(APP_SERVICES ApplicationServices) FIND_LIBRARY(APP_SERVICES ApplicationServices)
set(${MODULE_PREFIX}_SRCS set(${MODULE_PREFIX}_SRCS
audin_mac.c) audin_mac.m)
include_directories(..) include_directories(..)
include_directories(${MAC_INCLUDE_DIRS}) include_directories(${MAC_INCLUDE_DIRS})
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "") add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
set(${MODULE_PREFIX}_LIBS freerdp ${CORE_AUDIO} ${AUDIO_TOOL} ${APP_SERVICES} winpr) set(${MODULE_PREFIX}_LIBS freerdp ${AVFOUNDATION} ${CORE_AUDIO} ${AUDIO_TOOL} ${APP_SERVICES} winpr)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

View File

@ -33,12 +33,14 @@
#include <winpr/debug.h> #include <winpr/debug.h>
#include <winpr/cmdline.h> #include <winpr/cmdline.h>
#import <AVFoundation/AVFoundation.h>
#define __COREFOUNDATION_CFPLUGINCOM__ 1 #define __COREFOUNDATION_CFPLUGINCOM__ 1
#define IUNKNOWN_C_GUTS \ #define IUNKNOWN_C_GUTS \
void* _reserved; \ void *_reserved; \
void* QueryInterface; \ void *QueryInterface; \
void* AddRef; \ void *AddRef; \
void* Release void *Release
#include <CoreAudio/CoreAudioTypes.h> #include <CoreAudio/CoreAudioTypes.h>
#include <CoreAudio/CoreAudio.h> #include <CoreAudio/CoreAudio.h>
@ -72,17 +74,18 @@ typedef struct _AudinMacDevice
int dev_unit; int dev_unit;
AudinReceive receive; AudinReceive receive;
void* user_data; void *user_data;
rdpContext* rdpcontext; rdpContext *rdpcontext;
bool isAuthorized;
bool isOpen; bool isOpen;
AudioQueueRef audioQueue; AudioQueueRef audioQueue;
AudioStreamBasicDescription audioFormat; AudioStreamBasicDescription audioFormat;
AudioQueueBufferRef audioBuffers[MAC_AUDIO_QUEUE_NUM_BUFFERS]; AudioQueueBufferRef audioBuffers[MAC_AUDIO_QUEUE_NUM_BUFFERS];
} AudinMacDevice; } AudinMacDevice;
static AudioFormatID audin_mac_get_format(const AUDIO_FORMAT* format) static AudioFormatID audin_mac_get_format(const AUDIO_FORMAT *format)
{ {
switch (format->wFormatTag) switch (format->wFormatTag)
{ {
@ -94,7 +97,7 @@ static AudioFormatID audin_mac_get_format(const AUDIO_FORMAT* format)
} }
} }
static AudioFormatFlags audin_mac_get_flags_for_format(const AUDIO_FORMAT* format) static AudioFormatFlags audin_mac_get_flags_for_format(const AUDIO_FORMAT *format)
{ {
switch (format->wFormatTag) switch (format->wFormatTag)
{ {
@ -106,10 +109,14 @@ static AudioFormatFlags audin_mac_get_flags_for_format(const AUDIO_FORMAT* forma
} }
} }
static BOOL audin_mac_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format) static BOOL audin_mac_format_supported(IAudinDevice *device, const AUDIO_FORMAT *format)
{ {
AudinMacDevice *mac = (AudinMacDevice *)device;
AudioFormatID req_fmt = 0; AudioFormatID req_fmt = 0;
if (!mac->isAuthorized)
return FALSE;
if (device == NULL || format == NULL) if (device == NULL || format == NULL)
return FALSE; return FALSE;
@ -126,10 +133,13 @@ static BOOL audin_mac_format_supported(IAudinDevice* device, const AUDIO_FORMAT*
* *
* @return 0 on success, otherwise a Win32 error code * @return 0 on success, otherwise a Win32 error code
*/ */
static UINT audin_mac_set_format(IAudinDevice* device, const AUDIO_FORMAT* format, static UINT audin_mac_set_format(IAudinDevice *device, const AUDIO_FORMAT *format,
UINT32 FramesPerPacket) UINT32 FramesPerPacket)
{ {
AudinMacDevice* mac = (AudinMacDevice*)device; AudinMacDevice *mac = (AudinMacDevice *)device;
if (!mac->isAuthorized)
return ERROR_INTERNAL_ERROR;
if (device == NULL || format == NULL) if (device == NULL || format == NULL)
return ERROR_INVALID_PARAMETER; return ERROR_INVALID_PARAMETER;
@ -155,13 +165,13 @@ static UINT audin_mac_set_format(IAudinDevice* device, const AUDIO_FORMAT* forma
return CHANNEL_RC_OK; return CHANNEL_RC_OK;
} }
static void mac_audio_queue_input_cb(void* aqData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer, static void mac_audio_queue_input_cb(void *aqData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer,
const AudioTimeStamp* inStartTime, UInt32 inNumPackets, const AudioTimeStamp *inStartTime, UInt32 inNumPackets,
const AudioStreamPacketDescription* inPacketDesc) const AudioStreamPacketDescription *inPacketDesc)
{ {
AudinMacDevice* mac = (AudinMacDevice*)aqData; AudinMacDevice *mac = (AudinMacDevice *)aqData;
UINT error = CHANNEL_RC_OK; UINT error = CHANNEL_RC_OK;
const BYTE* buffer = inBuffer->mAudioData; const BYTE *buffer = inBuffer->mAudioData;
int buffer_size = inBuffer->mAudioDataByteSize; int buffer_size = inBuffer->mAudioDataByteSize;
(void)inAQ; (void)inAQ;
(void)inStartTime; (void)inStartTime;
@ -180,12 +190,15 @@ static void mac_audio_queue_input_cb(void* aqData, AudioQueueRef inAQ, AudioQueu
} }
} }
static UINT audin_mac_close(IAudinDevice* device) static UINT audin_mac_close(IAudinDevice *device)
{ {
UINT errCode = CHANNEL_RC_OK; UINT errCode = CHANNEL_RC_OK;
char errString[1024]; char errString[1024];
OSStatus devStat; OSStatus devStat;
AudinMacDevice* mac = (AudinMacDevice*)device; AudinMacDevice *mac = (AudinMacDevice *)device;
if (!mac->isAuthorized)
return ERROR_INTERNAL_ERROR;
if (device == NULL) if (device == NULL)
return ERROR_INVALID_PARAMETER; return ERROR_INVALID_PARAMETER;
@ -223,13 +236,17 @@ static UINT audin_mac_close(IAudinDevice* device)
return errCode; return errCode;
} }
static UINT audin_mac_open(IAudinDevice* device, AudinReceive receive, void* user_data) static UINT audin_mac_open(IAudinDevice *device, AudinReceive receive, void *user_data)
{ {
AudinMacDevice* mac = (AudinMacDevice*)device; AudinMacDevice *mac = (AudinMacDevice *)device;
DWORD errCode; DWORD errCode;
char errString[1024]; char errString[1024];
OSStatus devStat; OSStatus devStat;
size_t index; size_t index;
if (!mac->isAuthorized)
return ERROR_INTERNAL_ERROR;
mac->receive = receive; mac->receive = receive;
mac->user_data = user_data; mac->user_data = user_data;
devStat = AudioQueueNewInput(&(mac->audioFormat), mac_audio_queue_input_cb, mac, NULL, devStat = AudioQueueNewInput(&(mac->audioFormat), mac_audio_queue_input_cb, mac, NULL,
@ -285,9 +302,9 @@ err_out:
return CHANNEL_RC_INITIALIZATION_ERROR; return CHANNEL_RC_INITIALIZATION_ERROR;
} }
static UINT audin_mac_free(IAudinDevice* device) static UINT audin_mac_free(IAudinDevice *device)
{ {
AudinMacDevice* mac = (AudinMacDevice*)device; AudinMacDevice *mac = (AudinMacDevice *)device;
int error; int error;
if (device == NULL) if (device == NULL)
@ -302,19 +319,19 @@ static UINT audin_mac_free(IAudinDevice* device)
return CHANNEL_RC_OK; return CHANNEL_RC_OK;
} }
static UINT audin_mac_parse_addin_args(AudinMacDevice* device, ADDIN_ARGV* args) static UINT audin_mac_parse_addin_args(AudinMacDevice *device, ADDIN_ARGV *args)
{ {
DWORD errCode; DWORD errCode;
char errString[1024]; char errString[1024];
int status; int status;
char *str_num, *eptr; char *str_num, *eptr;
DWORD flags; DWORD flags;
COMMAND_LINE_ARGUMENT_A* arg; COMMAND_LINE_ARGUMENT_A *arg;
COMMAND_LINE_ARGUMENT_A audin_mac_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", COMMAND_LINE_ARGUMENT_A audin_mac_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>",
NULL, NULL, -1, NULL, "audio device name" }, NULL, NULL, -1, NULL, "audio device name" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } };
AudinMacDevice* mac = (AudinMacDevice*)device; AudinMacDevice *mac = (AudinMacDevice *)device;
if (args->argc == 1) if (args->argc == 1)
return CHANNEL_RC_OK; return CHANNEL_RC_OK;
@ -369,10 +386,10 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn
{ {
DWORD errCode; DWORD errCode;
char errString[1024]; char errString[1024];
ADDIN_ARGV* args; ADDIN_ARGV *args;
AudinMacDevice* mac; AudinMacDevice *mac;
UINT error; UINT error;
mac = (AudinMacDevice*)calloc(1, sizeof(AudinMacDevice)); mac = (AudinMacDevice *)calloc(1, sizeof(AudinMacDevice));
if (!mac) if (!mac)
{ {
@ -397,12 +414,40 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn
goto error_out; goto error_out;
} }
if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*)mac))) if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice *)mac)))
{ {
WLog_ERR(TAG, "RegisterAudinDevice failed with error %" PRIu32 "!", error); WLog_ERR(TAG, "RegisterAudinDevice failed with error %" PRIu32 "!", error);
goto error_out; goto error_out;
} }
AVAuthorizationStatus status =
[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
switch (status)
{
case AVAuthorizationStatusAuthorized:
mac->isAuthorized = TRUE;
break;
case AVAuthorizationStatusNotDetermined:
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo
completionHandler:^(BOOL granted) {
if (granted == YES)
{
mac->isAuthorized = TRUE;
}
else
WLog_WARN(TAG, "Microphone access denied by user");
}];
break;
case AVAuthorizationStatusRestricted:
WLog_WARN(TAG, "Microphone access restricted by policy");
break;
case AVAuthorizationStatusDenied:
WLog_WARN(TAG, "Microphone access denied by policy");
break;
default:
break;
}
return CHANNEL_RC_OK; return CHANNEL_RC_OK;
error_out: error_out:
free(mac); free(mac);

View File

@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>NSCameraUsageDescription</key>
<string>This application requires camera access to redirect it to the remote host</string>
<key>NSMicrophoneUsageDescription</key>
<string>This application requires microphone access to redirect it to the remote host</string>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>English</string> <string>English</string>
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>

View File

@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>NSCameraUsageDescription</key>
<string>This application requires camera access to redirect it to the remote host</string>
<key>NSMicrophoneUsageDescription</key>
<string>This application requires microphone access to redirect it to the remote host</string>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>en</string> <string>en</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>