mirror of
https://github.com/racecarparts/MuteUnmuteMic.git
synced 2026-04-16 18:55:41 +02:00
Added hardware mute via core audio
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
D9A9F66F1BC35EDC004395E8 /* AudioMixer.c in Sources */ = {isa = PBXBuildFile; fileRef = D9A9F66D1BC35EDC004395E8 /* AudioMixer.c */; settings = {ASSET_TAGS = (); }; };
|
||||
ECF208BE1BAF2DE6000D3C2C /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = ECF208BD1BAF2DE6000D3C2C /* AppDelegate.m */; };
|
||||
ECF208C11BAF2DE6000D3C2C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = ECF208C01BAF2DE6000D3C2C /* main.m */; };
|
||||
ECF208C31BAF2DE6000D3C2C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = ECF208C21BAF2DE6000D3C2C /* Assets.xcassets */; };
|
||||
@@ -14,6 +15,8 @@
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
D9A9F66D1BC35EDC004395E8 /* AudioMixer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = AudioMixer.c; path = MuteUnmuteMic/AudioMixer.c; sourceTree = "<group>"; };
|
||||
D9A9F66E1BC35EDC004395E8 /* AudioMixer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioMixer.h; path = MuteUnmuteMic/AudioMixer.h; sourceTree = "<group>"; };
|
||||
ECF208B91BAF2DE6000D3C2C /* MuteUnmuteMic.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MuteUnmuteMic.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
ECF208BC1BAF2DE6000D3C2C /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
ECF208BD1BAF2DE6000D3C2C /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||
@@ -39,6 +42,8 @@
|
||||
children = (
|
||||
ECF208BB1BAF2DE6000D3C2C /* MuteUnmuteMic */,
|
||||
ECF208BA1BAF2DE6000D3C2C /* Products */,
|
||||
D9A9F66D1BC35EDC004395E8 /* AudioMixer.c */,
|
||||
D9A9F66E1BC35EDC004395E8 /* AudioMixer.h */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -142,6 +147,7 @@
|
||||
files = (
|
||||
ECF208C11BAF2DE6000D3C2C /* main.m in Sources */,
|
||||
ECF208BE1BAF2DE6000D3C2C /* AppDelegate.m in Sources */,
|
||||
D9A9F66F1BC35EDC004395E8 /* AudioMixer.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -1,32 +1,37 @@
|
||||
#import "AppDelegate.h"
|
||||
#import "AudioMixer.h"
|
||||
|
||||
#define MAX_VOLUME 70
|
||||
static NSInteger const kDefaultVolume = 70;
|
||||
|
||||
@interface AppDelegate ()
|
||||
{
|
||||
NSStatusItem *menuItem;
|
||||
BOOL muted;
|
||||
int inputVolumeToUnmute;
|
||||
}
|
||||
|
||||
@property (nonatomic) NSStatusItem *menuItem;
|
||||
@property (nonatomic) BOOL muted;
|
||||
@property (nonatomic) NSInteger inputVolumeToUnmute;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
||||
{
|
||||
[self initDefaults];
|
||||
[self configureStatusBar];
|
||||
[self updateInputVolume];
|
||||
}
|
||||
|
||||
- (void)initDefaults {
|
||||
muted = NO;
|
||||
inputVolumeToUnmute = MAX_VOLUME;
|
||||
- (void)initDefaults
|
||||
{
|
||||
_muted = IsHardwareMuted();
|
||||
_inputVolumeToUnmute = kDefaultVolume;
|
||||
}
|
||||
|
||||
- (void)configureStatusBar {
|
||||
- (void)configureStatusBar
|
||||
{
|
||||
NSStatusBar *statusBar = [NSStatusBar systemStatusBar];
|
||||
|
||||
menuItem = [statusBar statusItemWithLength:NSVariableStatusItemLength];
|
||||
NSStatusItem *menuItem =
|
||||
[statusBar statusItemWithLength:NSVariableStatusItemLength];
|
||||
[menuItem setToolTip:@"MuteUnmuteMic by CocoaHeads Brazil"];
|
||||
[menuItem setImage:[NSImage imageNamed:@"mic_on"]];
|
||||
[menuItem setHighlightMode:YES];
|
||||
@@ -34,9 +39,12 @@
|
||||
[menuItem setTarget:self];
|
||||
[menuItem setAction:@selector(menuItemClicked:)];
|
||||
[menuItem.button sendActionOn:NSLeftMouseUpMask|NSRightMouseUpMask];
|
||||
|
||||
self.menuItem = menuItem;
|
||||
}
|
||||
|
||||
- (void)menuItemClicked:(id)sender {
|
||||
- (void)menuItemClicked:(id)sender
|
||||
{
|
||||
NSEvent *event = [[NSApplication sharedApplication] currentEvent];
|
||||
|
||||
if ((event.modifierFlags & NSControlKeyMask) || (event.type == NSRightMouseUp)) {
|
||||
@@ -44,39 +52,59 @@
|
||||
} else {
|
||||
[self toggleMute];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (void)toggleMute {
|
||||
muted = !muted;
|
||||
- (void)toggleMute
|
||||
{
|
||||
self.muted = !self.muted;
|
||||
[self updateInputVolume];
|
||||
}
|
||||
|
||||
- (void)updateInputVolume {
|
||||
int volume = muted ? 0 : inputVolumeToUnmute;
|
||||
NSString *source = [NSString stringWithFormat:@"set volume input volume %d", volume];
|
||||
- (void)updateInputVolume
|
||||
{
|
||||
BOOL muted = self.muted;
|
||||
|
||||
NSInteger volume;
|
||||
NSString *imageName;
|
||||
if (muted) {
|
||||
volume = 0;
|
||||
imageName = @"mic_off";
|
||||
} else {
|
||||
volume = self.inputVolumeToUnmute;
|
||||
imageName = @"mic_on";
|
||||
}
|
||||
|
||||
// set volume
|
||||
NSString *source =
|
||||
[NSString stringWithFormat:@"set volume input volume %ld", (long)volume];
|
||||
NSAppleScript *script = [[NSAppleScript alloc] initWithSource:source];
|
||||
NSDictionary *errorInfo = nil;
|
||||
[script executeAndReturnError:&errorInfo];
|
||||
|
||||
[script executeAndReturnError:nil];
|
||||
if (errorInfo) {
|
||||
NSLog(@"Error on script %@", errorInfo);
|
||||
}
|
||||
|
||||
NSString *imageName = muted ? @"mic_off" : @"mic_on";
|
||||
menuItem.image = [NSImage imageNamed:imageName];
|
||||
|
||||
// set hardware mute
|
||||
SetHardwareMute(muted);
|
||||
|
||||
// set image
|
||||
self.menuItem.image = [NSImage imageNamed:imageName];
|
||||
}
|
||||
|
||||
- (void)showMenu {
|
||||
[menuItem popUpStatusItemMenu:self.menu];
|
||||
- (void)showMenu
|
||||
{
|
||||
[self.menuItem popUpStatusItemMenu:self.menu];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction)didSetVolumeInput:(NSMenuItem *)sender {
|
||||
|
||||
- (IBAction)didSetVolumeInput:(NSMenuItem *)sender
|
||||
{
|
||||
for (NSMenuItem *item in sender.menu.itemArray) {
|
||||
item.state = 0;
|
||||
}
|
||||
sender.state = 1;
|
||||
|
||||
inputVolumeToUnmute = [sender.title intValue];
|
||||
self.inputVolumeToUnmute = [sender.title integerValue];
|
||||
[self updateInputVolume];
|
||||
}
|
||||
|
||||
|
||||
154
MuteUnmuteMic/AudioMixer.c
Normal file
154
MuteUnmuteMic/AudioMixer.c
Normal file
@@ -0,0 +1,154 @@
|
||||
//
|
||||
// AudioMixer.c
|
||||
// MuteUnmuteMic
|
||||
//
|
||||
// Created by Diogo Tridapalli on 10/5/15.
|
||||
// Copyright © 2015 Gustavo Barbosa. All rights reserved.
|
||||
//
|
||||
|
||||
#include "AudioMixer.h"
|
||||
|
||||
Boolean GetDefaultInputAudioDevice(AudioDeviceID *defaultInputDeviceID)
|
||||
{
|
||||
UInt32 thePropSize = sizeof(AudioDeviceID);
|
||||
|
||||
AudioObjectPropertyAddress thePropertyAddress =
|
||||
{ kAudioHardwarePropertyDefaultInputDevice,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMaster };
|
||||
|
||||
OSStatus errorCode =
|
||||
AudioObjectGetPropertyData(kAudioObjectSystemObject,
|
||||
&thePropertyAddress,
|
||||
0,
|
||||
NULL,
|
||||
&thePropSize,
|
||||
defaultInputDeviceID);
|
||||
if (errorCode) {
|
||||
printf("Error in GetDefaultInputAudioDevice: %d\n", errorCode);
|
||||
}
|
||||
|
||||
return errorCode == 0;
|
||||
}
|
||||
|
||||
Boolean GetAudioDeviceName(const AudioDeviceID deviceID,
|
||||
CFStringRef *deviceName)
|
||||
{
|
||||
UInt32 thePropSize = sizeof(CFStringRef);
|
||||
AudioObjectPropertyAddress thePropertyAddress =
|
||||
{ kAudioObjectPropertyName,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMaster };
|
||||
|
||||
OSStatus errorCode =
|
||||
AudioObjectGetPropertyData(deviceID,
|
||||
&thePropertyAddress,
|
||||
0,
|
||||
NULL,
|
||||
&thePropSize,
|
||||
deviceName);
|
||||
|
||||
if (errorCode) {
|
||||
printf("Error in GetAudioDeviceName: %d\n", errorCode);
|
||||
}
|
||||
|
||||
return errorCode == 0;
|
||||
}
|
||||
|
||||
Boolean GetMuteOnInputAudioDevice(const AudioDeviceID inputDeviceID,
|
||||
Boolean *isMuted)
|
||||
{
|
||||
AudioObjectPropertyAddress thePropertyAddress =
|
||||
{ kAudioDevicePropertyMute,
|
||||
kAudioDevicePropertyScopeInput,
|
||||
kAudioObjectPropertyElementMaster };
|
||||
|
||||
UInt32 mute = 0;
|
||||
UInt32 thePropSize = sizeof(mute);
|
||||
|
||||
OSStatus errorCode;
|
||||
if (AudioObjectHasProperty(inputDeviceID, &thePropertyAddress)) {
|
||||
errorCode = AudioObjectGetPropertyData(inputDeviceID,
|
||||
&thePropertyAddress,
|
||||
0,
|
||||
NULL,
|
||||
&thePropSize,
|
||||
&mute);
|
||||
if (errorCode) {
|
||||
printf("Error in GetMuteOnInputAudioDevice: %d\n", errorCode);
|
||||
}
|
||||
|
||||
*isMuted = mute > 0;
|
||||
|
||||
return errorCode == 0;
|
||||
} else {
|
||||
printf("Error in GetMuteOnInputAudioDevice: mute not supported\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Boolean SetMuteOnInputAudioDevice(const AudioDeviceID inputDeviceID,
|
||||
const Boolean mute)
|
||||
{
|
||||
AudioObjectPropertyAddress thePropertyAddress =
|
||||
{ kAudioDevicePropertyMute,
|
||||
kAudioDevicePropertyScopeInput,
|
||||
kAudioObjectPropertyElementMaster };
|
||||
|
||||
UInt32 theMute = mute;
|
||||
UInt32 thePropSize = sizeof(theMute);
|
||||
|
||||
|
||||
const char *inputDeviceString;
|
||||
CFStringRef inputDeviceName;
|
||||
if (GetAudioDeviceName(inputDeviceID, &inputDeviceName)) {
|
||||
inputDeviceString =
|
||||
CFStringGetCStringPtr(inputDeviceName, CFStringGetSystemEncoding());
|
||||
CFRelease(inputDeviceName);
|
||||
} else {
|
||||
inputDeviceString = "<Unamed device>";
|
||||
}
|
||||
|
||||
Boolean setMute = true;
|
||||
|
||||
if (AudioObjectHasProperty(inputDeviceID, &thePropertyAddress)) {
|
||||
printf("\tSetting %s mute %s\n", inputDeviceString, (theMute) ? "on" : "off");
|
||||
OSStatus errorCode = AudioObjectSetPropertyData(inputDeviceID,
|
||||
&thePropertyAddress,
|
||||
0,
|
||||
NULL,
|
||||
thePropSize,
|
||||
&theMute);
|
||||
if (errorCode) {
|
||||
printf("Error in SetMuteOnInputAudioDevice: %d\n", errorCode);
|
||||
setMute = false;
|
||||
}
|
||||
} else {
|
||||
printf("Error in SetMuteOnInputAudioDevice: mute not supported\n");
|
||||
setMute = false;
|
||||
}
|
||||
|
||||
return setMute;
|
||||
}
|
||||
|
||||
Boolean IsHardwareMuted()
|
||||
{
|
||||
AudioDeviceID theDefaultInputDeviceID;
|
||||
|
||||
Boolean isMuted = false;
|
||||
|
||||
if (GetDefaultInputAudioDevice(&theDefaultInputDeviceID)) {
|
||||
GetMuteOnInputAudioDevice(theDefaultInputDeviceID, &isMuted);
|
||||
}
|
||||
|
||||
return isMuted;
|
||||
}
|
||||
|
||||
void SetHardwareMute(Boolean theMute)
|
||||
{
|
||||
AudioDeviceID theDefaultInputDeviceID;
|
||||
if (GetDefaultInputAudioDevice(&theDefaultInputDeviceID)) {
|
||||
SetMuteOnInputAudioDevice(theDefaultInputDeviceID, theMute);
|
||||
}
|
||||
}
|
||||
69
MuteUnmuteMic/AudioMixer.h
Normal file
69
MuteUnmuteMic/AudioMixer.h
Normal file
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// AudioMixer.h
|
||||
// MuteUnmuteMic
|
||||
//
|
||||
// Created by Diogo Tridapalli on 10/5/15.
|
||||
// Copyright © 2015 Gustavo Barbosa. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef AudioMixer_h
|
||||
#define AudioMixer_h
|
||||
|
||||
#import <CoreAudio/CoreAudio.h>
|
||||
/**
|
||||
* Get device id for the default input device
|
||||
*
|
||||
* @param defaultInputDeviceID AudioDeviceID pointer
|
||||
*
|
||||
* @return @a true if success @a false otherwise
|
||||
*/
|
||||
extern Boolean GetDefaultInputAudioDevice(AudioDeviceID *defaultInputDeviceID);
|
||||
|
||||
/**
|
||||
* Get the name of an audio device
|
||||
*
|
||||
* @param deviceID AudioDeviceID
|
||||
* @param deviceName CFStringRef reference, must be release after use
|
||||
*
|
||||
* @return @a true if success @a false otherwise
|
||||
*/
|
||||
extern Boolean GetAudioDeviceName(const AudioDeviceID deviceID,
|
||||
CFStringRef *deviceName);
|
||||
|
||||
/**
|
||||
* Get mute state on input device
|
||||
*
|
||||
* @param inputDeviceID AudioDeviceID
|
||||
* @param isMuted @a true if device is muted @a false otherwise
|
||||
*
|
||||
* @return @a true if success @a false otherwise
|
||||
*/
|
||||
extern Boolean GetMuteOnInputAudioDevice(const AudioDeviceID inputDeviceID,
|
||||
Boolean *isMuted);
|
||||
|
||||
/**
|
||||
* Mute or unmute an inpute device
|
||||
*
|
||||
* @param inputDeviceID AudioDeviceID
|
||||
* @param mute @a true if device should be muted @a false otherwise
|
||||
*
|
||||
* @return @a true if success @a false otherwise
|
||||
*/
|
||||
extern Boolean SetMuteOnInputAudioDevice(const AudioDeviceID inputDeviceID,
|
||||
const Boolean mute);
|
||||
|
||||
/**
|
||||
* Get the mute state of default input via HAL
|
||||
*
|
||||
* @return @a true if is muted @a false otherwise
|
||||
*/
|
||||
extern Boolean IsHardwareMuted();
|
||||
|
||||
/**
|
||||
* Set the mute state of default input via HAL
|
||||
*
|
||||
* @param theMute @a true if should be muted @a false otherwise
|
||||
*/
|
||||
extern void SetHardwareMute(Boolean theMute);
|
||||
|
||||
#endif /* AudioMixer_h */
|
||||
Reference in New Issue
Block a user