//
// Device.mm
// obs-mac-virtualcam
//
// Created by John Boiles on 4/10/20.
//
// obs-mac-virtualcam is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// obs-mac-virtualcam is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with obs-mac-virtualcam. If not, see .
#import "OBSDALDevice.h"
#include
#import "OBSDALPlugIn.h"
#import "Logging.h"
@interface OBSDALDevice ()
@property BOOL excludeNonDALAccess;
@property pid_t masterPid;
@end
@implementation OBSDALDevice
// Note that the DAL's API calls HasProperty before calling GetPropertyDataSize. This means that it can be assumed that address is valid for the property involved.
- (UInt32)getPropertyDataSizeWithAddress:(CMIOObjectPropertyAddress)address
qualifierDataSize:(UInt32)qualifierDataSize
qualifierData:(nonnull const void *)qualifierData
{
switch (address.mSelector) {
case kCMIOObjectPropertyName:
return sizeof(CFStringRef);
case kCMIOObjectPropertyManufacturer:
return sizeof(CFStringRef);
case kCMIOObjectPropertyElementCategoryName:
return sizeof(CFStringRef);
case kCMIOObjectPropertyElementNumberName:
return sizeof(CFStringRef);
case kCMIODevicePropertyPlugIn:
return sizeof(CMIOObjectID);
case kCMIODevicePropertyDeviceUID:
return sizeof(CFStringRef);
case kCMIODevicePropertyModelUID:
return sizeof(CFStringRef);
case kCMIODevicePropertyTransportType:
return sizeof(UInt32);
case kCMIODevicePropertyDeviceIsAlive:
return sizeof(UInt32);
case kCMIODevicePropertyDeviceHasChanged:
return sizeof(UInt32);
case kCMIODevicePropertyDeviceIsRunning:
return sizeof(UInt32);
case kCMIODevicePropertyDeviceIsRunningSomewhere:
return sizeof(UInt32);
case kCMIODevicePropertyDeviceCanBeDefaultDevice:
return sizeof(UInt32);
case kCMIODevicePropertyHogMode:
return sizeof(pid_t);
case kCMIODevicePropertyLatency:
return sizeof(UInt32);
case kCMIODevicePropertyStreams:
// Only one stream
return sizeof(CMIOStreamID) * 1;
case kCMIODevicePropertyStreamConfiguration:
// Only one stream
return sizeof(UInt32) + (sizeof(UInt32) * 1);
case kCMIODevicePropertyExcludeNonDALAccess:
return sizeof(UInt32);
case kCMIODevicePropertyCanProcessAVCCommand:
return sizeof(Boolean);
case kCMIODevicePropertyCanProcessRS422Command:
return sizeof(Boolean);
case kCMIODevicePropertyLinkedCoreAudioDeviceUID:
return sizeof(CFStringRef);
case kCMIODevicePropertyDeviceMaster:
return sizeof(pid_t);
default:
break;
};
return 0;
}
// Note that the DAL's API calls HasProperty before calling GetPropertyData. This means that it can be assumed that address is valid for the property involved.
- (void)getPropertyDataWithAddress:(CMIOObjectPropertyAddress)address
qualifierDataSize:(UInt32)qualifierDataSize
qualifierData:(nonnull const void *)qualifierData
dataSize:(UInt32)dataSize
dataUsed:(nonnull UInt32 *)dataUsed
data:(nonnull void *)data
{
switch (address.mSelector) {
case kCMIOObjectPropertyName:
*static_cast(data) = CFSTR("OBS Virtual Camera");
*dataUsed = sizeof(CFStringRef);
break;
case kCMIOObjectPropertyManufacturer:
*static_cast(data) = CFSTR("John Boiles");
*dataUsed = sizeof(CFStringRef);
break;
case kCMIOObjectPropertyElementCategoryName:
*static_cast(data) = CFSTR("Virtual Camera");
*dataUsed = sizeof(CFStringRef);
break;
case kCMIOObjectPropertyElementNumberName:
*static_cast(data) = CFSTR("0001");
*dataUsed = sizeof(CFStringRef);
break;
case kCMIODevicePropertyPlugIn:
*static_cast(data) = self.pluginId;
*dataUsed = sizeof(CMIOObjectID);
break;
case kCMIODevicePropertyDeviceUID:
*static_cast(data) = CFSTR("obs-virtual-cam-device");
*dataUsed = sizeof(CFStringRef);
break;
case kCMIODevicePropertyModelUID:
*static_cast(data) = CFSTR("obs-virtual-cam-model");
*dataUsed = sizeof(CFStringRef);
break;
case kCMIODevicePropertyTransportType:
*static_cast(data) = kIOAudioDeviceTransportTypeBuiltIn;
*dataUsed = sizeof(UInt32);
break;
case kCMIODevicePropertyDeviceIsAlive:
*static_cast(data) = 1;
*dataUsed = sizeof(UInt32);
break;
case kCMIODevicePropertyDeviceHasChanged:
*static_cast(data) = 0;
*dataUsed = sizeof(UInt32);
break;
case kCMIODevicePropertyDeviceIsRunning:
*static_cast(data) = 1;
*dataUsed = sizeof(UInt32);
break;
case kCMIODevicePropertyDeviceIsRunningSomewhere:
*static_cast(data) = 1;
*dataUsed = sizeof(UInt32);
break;
case kCMIODevicePropertyDeviceCanBeDefaultDevice:
*static_cast(data) = 1;
*dataUsed = sizeof(UInt32);
break;
case kCMIODevicePropertyHogMode:
*static_cast(data) = -1;
*dataUsed = sizeof(pid_t);
break;
case kCMIODevicePropertyLatency:
*static_cast(data) = 0;
*dataUsed = sizeof(UInt32);
break;
case kCMIODevicePropertyStreams:
*static_cast(data) = self.streamId;
*dataUsed = sizeof(CMIOObjectID);
break;
case kCMIODevicePropertyStreamConfiguration:
DLog(@"TODO kCMIODevicePropertyStreamConfiguration");
break;
case kCMIODevicePropertyExcludeNonDALAccess:
*static_cast(data) = self.excludeNonDALAccess ? 1 : 0;
*dataUsed = sizeof(UInt32);
break;
case kCMIODevicePropertyCanProcessAVCCommand:
*static_cast(data) = false;
*dataUsed = sizeof(Boolean);
break;
case kCMIODevicePropertyCanProcessRS422Command:
*static_cast(data) = false;
*dataUsed = sizeof(Boolean);
break;
case kCMIODevicePropertyDeviceMaster:
*static_cast(data) = self.masterPid;
*dataUsed = sizeof(pid_t);
break;
default:
break;
};
}
- (BOOL)hasPropertyWithAddress:(CMIOObjectPropertyAddress)address
{
switch (address.mSelector) {
case kCMIOObjectPropertyName:
case kCMIOObjectPropertyManufacturer:
case kCMIOObjectPropertyElementCategoryName:
case kCMIOObjectPropertyElementNumberName:
case kCMIODevicePropertyPlugIn:
case kCMIODevicePropertyDeviceUID:
case kCMIODevicePropertyModelUID:
case kCMIODevicePropertyTransportType:
case kCMIODevicePropertyDeviceIsAlive:
case kCMIODevicePropertyDeviceHasChanged:
case kCMIODevicePropertyDeviceIsRunning:
case kCMIODevicePropertyDeviceIsRunningSomewhere:
case kCMIODevicePropertyDeviceCanBeDefaultDevice:
case kCMIODevicePropertyHogMode:
case kCMIODevicePropertyLatency:
case kCMIODevicePropertyStreams:
case kCMIODevicePropertyExcludeNonDALAccess:
case kCMIODevicePropertyCanProcessAVCCommand:
case kCMIODevicePropertyCanProcessRS422Command:
case kCMIODevicePropertyDeviceMaster:
return true;
case kCMIODevicePropertyStreamConfiguration:
case kCMIODevicePropertyLinkedCoreAudioDeviceUID:
return false;
default:
return false;
};
}
- (BOOL)isPropertySettableWithAddress:(CMIOObjectPropertyAddress)address
{
switch (address.mSelector) {
case kCMIOObjectPropertyName:
case kCMIOObjectPropertyManufacturer:
case kCMIOObjectPropertyElementCategoryName:
case kCMIOObjectPropertyElementNumberName:
case kCMIODevicePropertyPlugIn:
case kCMIODevicePropertyDeviceUID:
case kCMIODevicePropertyModelUID:
case kCMIODevicePropertyTransportType:
case kCMIODevicePropertyDeviceIsAlive:
case kCMIODevicePropertyDeviceHasChanged:
case kCMIODevicePropertyDeviceIsRunning:
case kCMIODevicePropertyDeviceIsRunningSomewhere:
case kCMIODevicePropertyDeviceCanBeDefaultDevice:
case kCMIODevicePropertyHogMode:
case kCMIODevicePropertyLatency:
case kCMIODevicePropertyStreams:
case kCMIODevicePropertyStreamConfiguration:
case kCMIODevicePropertyCanProcessAVCCommand:
case kCMIODevicePropertyCanProcessRS422Command:
case kCMIODevicePropertyLinkedCoreAudioDeviceUID:
return false;
case kCMIODevicePropertyExcludeNonDALAccess:
case kCMIODevicePropertyDeviceMaster:
return true;
default:
return false;
};
}
- (void)setPropertyDataWithAddress:(CMIOObjectPropertyAddress)address
qualifierDataSize:(UInt32)qualifierDataSize
qualifierData:(nonnull const void *)qualifierData
dataSize:(UInt32)dataSize
data:(nonnull const void *)data
{
switch (address.mSelector) {
case kCMIODevicePropertyExcludeNonDALAccess:
self.excludeNonDALAccess = (*static_cast(data) != 0);
break;
case kCMIODevicePropertyDeviceMaster:
self.masterPid = *static_cast(data);
break;
default:
break;
};
}
@end