How can I tell if the camera is in use by another process? - macos

In OS X, how can I tell if the camera or microphone is in use by another application or process? The following doesn't seem to work unless the other application has locked the device.
NSArray *devices = [AVCaptureDevice devices];
for (AVCaptureDevice *device in devices) {
NSLog(#"In use by other application %hhd", [device isInUseByAnotherApplication]);
}

You can use CoreAudio to check if microphone is in use or not.
AudioObjectPropertyAddress propertyAddress = {
kAudioHardwarePropertyDevices,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
UInt32 dataSize = 0;
OSStatus status = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize);
if(kAudioHardwareNoError != status) {
fprintf(stderr, "AudioObjectGetPropertyDataSize (kAudioHardwarePropertyDevices) failed: %i\n", status);
//return NULL;
return;
}
UInt32 deviceCount = (UInt32)(dataSize / sizeof(AudioDeviceID));
AudioDeviceID *audioDevices = (AudioDeviceID*)(malloc(dataSize));
if(NULL == audioDevices) {
fputs("Unable to allocate memory", stderr);
return;
}
status = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize, audioDevices);
if(kAudioHardwareNoError != status) {
fprintf(stderr, "AudioObjectGetPropertyData (kAudioHardwarePropertyDevices) failed: %i\n", status);
free(audioDevices), audioDevices = NULL;
return ;
}
CFMutableArrayRef inputDeviceArray = CFArrayCreateMutable(kCFAllocatorDefault, deviceCount, &kCFTypeArrayCallBacks);
if(NULL == inputDeviceArray) {
fputs("CFArrayCreateMutable failed", stderr);
free(audioDevices), audioDevices = NULL;
return ;
}`
Now Iterate through all the devices and fetch property data kAudioDevicePropertyDeviceIsRunningSomewhere
CFBooleanRef deviceIsRunning = NULL;
dataSize = sizeof(deviceIsRunning);
propertyAddress.mSelector = kAudioDevicePropertyDeviceIsRunningSomewhere;
status = AudioObjectGetPropertyData(audioDevices[i], &propertyAddress, 0, NULL, &dataSize, &deviceIsRunning);
Check deviceIsRunning variable.
I don't have idea about video device. But i will update my answer if i find some solution.
Hope this help.

I'm working on go module that detects camera/microphone state (using cgo) and here is my Objective-C implementations:
IsCameraOn(): https://github.com/antonfisher/go-media-devices-state/blob/main/pkg/camera/camera_darwin.mm
IsMicrophoneOn(): https://github.com/antonfisher/go-media-devices-state/blob/main/pkg/microphone/microphone_darwin.mm
Thanks #Rohan for the accepted answer!

Related

Can't get SID from DACL

I am trying to get the DACL of service, and then get the SIDs. Here is my code:
PSECURITY_DESCRIPTOR psd = NULL;
DWORD dwSize = 0;
DWORD dwBytesNeeded = 0;
BOOL bDaclPresent = FALSE; // tu Trua mashin aq DACL
PACL pacl = NULL;
BOOL bDaclDefaulted = FALSE;
PEXPLICIT_ACCESS bevri = NULL;
ULONG aq = 0;
char ** gio = NULL;
serviceManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
SC_HANDLE me = OpenService(serviceManager, serviceName, READ_CONTROL);
if (serviceManager == NULL)
{
fprintf(fp, "OpenService: fail %d\n.\n", GetLastError());
fflush(fp);
}
if (!QueryServiceObjectSecurity(me, DACL_SECURITY_INFORMATION, &psd, 0, &dwBytesNeeded))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
dwSize = dwBytesNeeded;
psd = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
if (psd == NULL)
{
fprintf(fp, "HeapAlloc failed\n");
fflush(fp);
}
if (!QueryServiceObjectSecurity(me, DACL_SECURITY_INFORMATION, psd, dwSize, &dwBytesNeeded))
{
fprintf(fp, "QueryServiceObjectSecurity failed %d\n", (int)GetLastError());
fflush(fp);
}
}
else
{
fprintf(fp, "QueryServiceObjectSecurity failed %d\n", (int)GetLastError());
fflush(fp);
}
}
if (!GetSecurityDescriptorDacl(psd, &bDaclPresent, &pacl, &bDaclDefaulted))
{
fprintf(fp, "GetSecurityDescriptorDacl failed %d\n", (int)GetLastError());
fflush(fp);
}
if (GetExplicitEntriesFromAcl(pacl, &aq, &bevri) != ERROR_SUCCESS)
{
fprintf(fp, "GetExplicitEntriesFromAcl: failed %d.\n", (int)GetLastError());
fflush(fp);
}
for (ULONG i = 0; i < aq; i++)
{
if (ConvertSidToStringSid(&bevri->Trustee.ptstrName[GetTrusteeForm(&bevri->Trustee)], gio) == 0)
{
fprintf(fp, "ConvertSidToStringSid: failed %d.\n", (int)GetLastError());
fflush(fp);
}
for (int index = 0; gio[index] != NULL; index++)
{
char * myString = gio[index];
fprintf(fp, "Value: %s\n",myString);
}
}
I've read in documentation that GetTrusteeForm function would indicate if Trustee has SID or name, it returned 0s which in TRUSTEE_FORM indicates to TRUSTEE_IS_SID. My problem is that I have ConvertSidToStringSid: failed 87. which is The parameter is incorrect.. I can't figure out why am I getting this. P.S. I'm sorry I know that this part of code is not really helpful to reproduce the issue, but I thought someone might knew what would problem be. Any help would be appriciated. Thanks.

AudioFileReadPackets Error -50

I'm playing with Audio API and my first step was to read the content of a file into the buffer.
I have the following code, but when AudioFileReadPackets is executed I get return code -50 which I don't get it, since in the documentation it doesn't exists.
Can you please point me to the right direction? Any idea will be appreciated!
//create url for file
CFURLRef myFileURL = CFURLCreateWithString(kCFAllocatorDefault, INPUT_FILE, NULL);
AudioFileID audioFile;
OSStatus error;
error = AudioFileOpenURL(myFileURL,kAudioFileReadPermission,0,&audioFile);
CFRelease(myFileURL);
if(error != noErr) {
printf("%d",(int)error);
exit(1);
}
AudioStreamBasicDescription dataFormat;
UInt32 size = sizeof(dataFormat);
error = AudioFileGetProperty(audioFile, kAudioFilePropertyDataFormat, &size, &dataFormat);
if(error != noErr) {
printf("%d",(int)error);
exit(1);
}
UInt32 dataSize;
error = AudioFileGetPropertyInfo(audioFile, kAudioFilePropertyAudioDataPacketCount, &dataSize, NULL);
if(error != noErr) {
printf("%d",(int)error);
exit(1);
}
UInt32 packetCount;
error = AudioFileGetProperty(audioFile, kAudioFilePropertyAudioDataPacketCount, &dataSize, &packetCount);
if(error != noErr) {
printf("%d",(int)error);
exit(1);
}
printf("File opened, packet count: %d\n", packetCount);
UInt32 packetsRead = packetCount;
UInt32 bytesRead = 0;
if(packetCount > 0) {
SInt16 audioData = *(SInt16 *)malloc(2 * packetCount);
error = AudioFileReadPackets(audioFile, false, &bytesRead, NULL, 0, &packetsRead, audioData);
if(error != noErr) {
printf("%d",(int)error);
exit(1);
}
printf("Read %d bytes, %d packets",bytesRead,packetsRead);
}
-50 = paramErr means you passed an incorrect parameter. Documentation says that the fourth parameter for AudioFileReadPackets must only be NULL for constant bitrate audio.

Cocoa Mac OSX application turn off sound

i have faced, witch simple quoestion, i didin't find in google, or in any forum. How to turn application audio/sound off? like mute? i wan't to make checkbox witch controlls sound of application.
I would be grateful for detailed definition
Try this from the source code:
- (void)setDefaultAudioDevice
{
UInt32 propertySize = 0;
OSStatus status = noErr;
AudioObjectPropertyAddress propertyAOPA;
propertyAOPA.mElement = kAudioObjectPropertyElementMaster;
propertyAOPA.mScope = kAudioObjectPropertyScopeGlobal;
propertyAOPA.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
propertySize = sizeof(AudioDeviceID);
status = AudioHardwareServiceGetPropertyData(kAudioObjectSystemObject, &propertyAOPA, 0, NULL, &propertySize, &outputDeviceID);
if(status)
{
// Error
return;
}
}
- (void)muteHardwareVolume
{
UInt32 propertySize = 0;
OSStatus status = noErr;
AudioObjectPropertyAddress propertyAOPA;
[self setDefaultAudioDevice];
propertyAOPA.mElement = kAudioObjectPropertyElementMaster;
propertyAOPA.mScope = kAudioDevicePropertyScopeOutput;
propertyAOPA.mSelector = kAudioDevicePropertyMute;
propertySize = sizeof(UInt32);
UInt32 mute = 1;
status = AudioHardwareServiceSetPropertyData(outputDeviceID, &propertyAOPA, 0, NULL, propertySize, &mute);
if(status)
{
// Error
return;
}
}

Programmatically change Mac display brightness

How to change Mac display brightness from cocoa application?
CGDisplayIOServicePort is deprecated in OS 10.9 – so you have to use IOServiceGetMatchingServices to get the service parameter for IODisplaySetFloatParameter. Here's a basic function that looks for services named "display" and changes their brightness.
- (void) setBrightnessTo: (float) level
{
io_iterator_t iterator;
kern_return_t result = IOServiceGetMatchingServices(kIOMasterPortDefault,
IOServiceMatching("IODisplayConnect"),
&iterator);
// If we were successful
if (result == kIOReturnSuccess)
{
io_object_t service;
while ((service = IOIteratorNext(iterator))) {
IODisplaySetFloatParameter(service, kNilOptions, CFSTR(kIODisplayBrightnessKey), level);
// Let the object go
IOObjectRelease(service);
return;
}
}
}
And in Swift (via #Dov):
private func setBrightnessLevel(level: Float) {
var iterator: io_iterator_t = 0
let result = IOServiceGetMatchingServices(kIOMasterPortDefault,
IOServiceMatching("IODisplayConnect").takeUnretainedValue(),
&iterator)
if result == kIOReturnSuccess {
var service: io_object_t = 1
for ;; {
service = IOIteratorNext(iterator)
if service == 0 {
break
}
IODisplaySetFloatParameter(service, 0, kIODisplayBrightnessKey, level)
IOObjectRelease(service)
}
}
}
(code is open source of course)
Expanding on Alex's answer:
In Xcode8 beta3 with Swift3, the code is a lot more streamlined.
private func setBrightness(level: Float) {
let service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IODisplayConnect"))
IODisplaySetFloatParameter(service, 0, kIODisplayBrightnessKey, level)
IOObjectRelease(service)
}
From Alec Jacobson's Brightness Menu source code:
- (void) set_brightness:(float) new_brightness {
CGDirectDisplayID display[kMaxDisplays];
CGDisplayCount numDisplays;
CGDisplayErr err;
err = CGGetActiveDisplayList(kMaxDisplays, display, &numDisplays);
if (err != CGDisplayNoErr)
printf("cannot get list of displays (error %d)\n",err);
for (CGDisplayCount i = 0; i < numDisplays; ++i) {
CGDirectDisplayID dspy = display[i];
CFDictionaryRef originalMode = CGDisplayCurrentMode(dspy);
if (originalMode == NULL)
continue;
io_service_t service = CGDisplayIOServicePort(dspy);
float brightness;
err= IODisplayGetFloatParameter(service, kNilOptions, kDisplayBrightness,
&brightness);
if (err != kIOReturnSuccess) {
fprintf(stderr,
"failed to get brightness of display 0x%x (error %d)",
(unsigned int)dspy, err);
continue;
}
err = IODisplaySetFloatParameter(service, kNilOptions, kDisplayBrightness,
new_brightness);
if (err != kIOReturnSuccess) {
fprintf(stderr,
"Failed to set brightness of display 0x%x (error %d)",
(unsigned int)dspy, err);
continue;
}
}
}
in Xcode 8 beta 6 does not compile:
IODisplaySetFloatParameter(service, 0, kIODisplayBrightnessKey, level)
Cannot convert value of type 'String' to expected argument type 'CFString!'
so let' cast it:
IODisplaySetFloatParameter(service, 0, kIODisplayBrightnessKey as CFString!, level)

how to get Audio Device UID to pass into NSSound's setPlaybackDeviceIdentifier:

How can i get audio device UID (USB speaker) to pass into NSSound's setPlaybackDeviceIdentifier: method
Thanks
To avoid the deprecated AudioHardwareGetProperty and AudioDeviceGetProperty calls replace them with something like this:
AudioObjectPropertyAddress propertyAddress;
AudioObjectID *deviceIDs;
UInt32 propertySize;
NSInteger numDevices;
propertyAddress.mSelector = kAudioHardwarePropertyDevices;
propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
propertyAddress.mElement = kAudioObjectPropertyElementMaster;
if (AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize) == noErr) {
numDevices = propertySize / sizeof(AudioDeviceID);
deviceIDs = (AudioDeviceID *)calloc(numDevices, sizeof(AudioDeviceID));
if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, deviceIDs) == noErr) {
AudioObjectPropertyAddress deviceAddress;
char deviceName[64];
char manufacturerName[64];
for (NSInteger idx=0; idx<numDevices; idx++) {
propertySize = sizeof(deviceName);
deviceAddress.mSelector = kAudioDevicePropertyDeviceName;
deviceAddress.mScope = kAudioObjectPropertyScopeGlobal;
deviceAddress.mElement = kAudioObjectPropertyElementMaster;
if (AudioObjectGetPropertyData(deviceIDs[idx], &deviceAddress, 0, NULL, &propertySize, deviceName) == noErr) {
propertySize = sizeof(manufacturerName);
deviceAddress.mSelector = kAudioDevicePropertyDeviceManufacturer;
deviceAddress.mScope = kAudioObjectPropertyScopeGlobal;
deviceAddress.mElement = kAudioObjectPropertyElementMaster;
if (AudioObjectGetPropertyData(deviceIDs[idx], &deviceAddress, 0, NULL, &propertySize, manufacturerName) == noErr) {
CFStringRef uidString;
propertySize = sizeof(uidString);
deviceAddress.mSelector = kAudioDevicePropertyDeviceUID;
deviceAddress.mScope = kAudioObjectPropertyScopeGlobal;
deviceAddress.mElement = kAudioObjectPropertyElementMaster;
if (AudioObjectGetPropertyData(deviceIDs[idx], &deviceAddress, 0, NULL, &propertySize, &uidString) == noErr) {
NSLog(#"device %s by %s id %#", deviceName, manufacturerName, uidString);
CFRelease(uidString);
}
}
}
}
}
free(deviceIDs);
}
ok i got it myself...
the theCFString will contain the device UID
UInt32 theSize;
char theString[kMaxStringSize];
UInt32 theNumberDevices;
AudioDeviceID *theDeviceList = NULL;
UInt32 theDeviceIndex;
CFStringRef theCFString = NULL;
OSStatus theStatus = noErr;
// this is our driver
const char *nameString = "Burr-Brown Japan PCM2702";
const char *manufacturerString = "Burr-Brown Japan";
// device list size
theSize = 0;
theStatus = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &theSize, NULL);
theNumberDevices = theSize / sizeof(AudioDeviceID);
// allocate the device list
theDeviceList = (AudioDeviceID*)malloc(theNumberDevices * sizeof(AudioDeviceID));
// get the device list
theSize = theNumberDevices * sizeof(AudioDeviceID);
theStatus = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &theSize, theDeviceList);
// iterate through the device list, find our device and return the UID
for(theDeviceIndex = 0; theDeviceIndex < theNumberDevices; ++theDeviceIndex)
{
// get name
theSize = kMaxStringSize;
theStatus = AudioDeviceGetProperty(theDeviceList[theDeviceIndex],
0, 0, kAudioDevicePropertyDeviceName, &theSize, theString);
NSLog(#"%s",theString);
// is it me?
if (strncmp(theString, nameString, strlen(nameString)) == 0) {
// get manufacturer
theSize = kMaxStringSize;
theStatus = AudioDeviceGetProperty(theDeviceList[theDeviceIndex], 0, 0,
kAudioDevicePropertyDeviceManufacturer, &theSize, theString);
NSLog(#"%s",theString);
// is it really me?
if (strncmp(theString, manufacturerString, strlen(manufacturerString)) == 0) {
// get device UID
theSize = sizeof(CFStringRef);
theStatus = AudioDeviceGetProperty(theDeviceList[theDeviceIndex],
0, 0, kAudioDevicePropertyDeviceUID, &theSize, &theCFString);
NSLog(#"%s",theCFString);
break;
}
}
}
AudioHardwareGetProperty is deprecated in snow leopard.

Resources