MAC OS

Mac OS的系统音量控制 - NSSlider控件操作

2021-05-25  本文已影响0人  goyohol


实现:操作一个滑动器(NSSlider),来控制Mac电脑的系统音量控制



先简单讲讲NSSlider控件:

let slider = NSSlider(frame: NSMakeRect(100, 100, 200, 50))
self.view .addSubview(slider)
//设置背景色
slider.wantsLayer = true
slider.layer?.backgroundColor = NSColor.cyan.cgColor
//minValue默认为0.0,maxValue默认为1.0
print("minValue:\(slider.minValue), maxValue:\(slider.maxValue)")
//添加操作的响应事件
slider.target = self;   slider.action = #selector(sliderValueChange)
//slider.controlSize = NSControl.ControlSize.mini   //滑块设置为最小
//if #available(macOS 11.0, *) {    //在macOS 11.0以上
//slider.controlSize = NSControl.ControlSize.large  //滑块设置为最大
//}

操作滑动器的响应事件:

@objc func sliderValueChange(slider: NSSlider) {//打印值(以各种类型)
    print("slider.objectValue = \(slider.objectValue as Any)")
    print("slider.intValue = \(slider.intValue)")
    print("slider.integerValue = \(slider.integerValue)")
    print("slider.floatValue = \(slider.floatValue)")
    print("slider.doubleValue = \(slider.doubleValue)")
}

效果:
a.minValue默认为0.0maxValue默认为1.0操作滑动器会打印当前的(范围0.0 ~ 1.0)!
b.在滑动器(青色背景色)范围内部即可对其进行操作

设置最小值、最大值——当设置minValue为1.0,maxValue为100.0!

//设置minValue为1.0,maxValue为100.0
slider.minValue = 10.0;    slider.maxValue = 100.0
print("after set! minValue:\(slider.minValue), maxValue:\(slider.maxValue)")

效果:minValue默认为10.0maxValue默认为100.0操作滑动器会打印当前的(范围10.0 ~ 100.0)!






实现功能(系统音量大小控制)时,就使用滑动器默认最小值最大值——minValue为0.0maxValue为1.0


Swift不太好实现。。(当然也不太想写,哈哈) 就用以前OC的代码书写了~(用个桥接来使用)

书写一个OC类(MacAudioVolumeObject):
1.选择'Cocoa Class'!2.使用Objective-C语言,继承自NSObject并命名为‘MacAudioVolumeObject’!3.选择'Create Bridging Header'创建桥接头文件后可进行桥接—可实现OC、Swift混编

1.选择'Cocoa Class' 2.使用Objective-C,继承自NSObject并命名为‘MacAudioVolumeObject’ 3.选择'Create Bridging Header'来桥接


MacAudioVolumeObject类——系统音量增大减小的功能实现:

.h文件

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface MacAudioVolumeObject : NSObject

//获取系统音量
+(float)getVolume;
//设置系统音量
+(void)setSystemVolumeValue:(Float32)newVolume;

@end

NS_ASSUME_NONNULL_END

.m文件

#import "MacAudioVolumeObject.h"

//导入调节音量所需的库:
@import AVFoundation;//必须
//#import <IOKit/IOKitLib.h>❌❌
//#import <IOKit/hidsystem/IOHIDLib.h>❌❌
//#import <IOKit/hidsystem/ev_keymap.h>❌❌

@implementation MacAudioVolumeObject

+(AudioDeviceID)getDefaultOutputDeviceID {
    AudioDeviceID outputDeviceID = kAudioObjectUnknown;//get output device
    
    OSStatus status = noErr;
    AudioObjectPropertyAddress propertyAOPA;
    propertyAOPA.mScope = kAudioObjectPropertyScopeGlobal;
    propertyAOPA.mElement = kAudioObjectPropertyElementMaster;
    propertyAOPA.mSelector = kAudioHardwarePropertyDefaultOutputDevice;

    if (!AudioHardwareServiceHasProperty(kAudioObjectSystemObject, &propertyAOPA))
    {
        printf("Cannot find default output device!");
        return outputDeviceID;
    }

    status = AudioHardwareServiceGetPropertyData(kAudioObjectSystemObject, &propertyAOPA, 0, NULL, (UInt32[]){sizeof(AudioDeviceID)}, &outputDeviceID);

    if (status != 0)
    {
        printf("Cannot find default output device!");
    }
    return outputDeviceID;
}

//获取系统音量
+(float)getVolume {
    Float32 outputVolume;
    
    OSStatus status = noErr;
    AudioObjectPropertyAddress propertyAOPA;
    propertyAOPA.mElement = kAudioObjectPropertyElementMaster;
    propertyAOPA.mSelector = kAudioHardwareServiceDeviceProperty_VirtualMasterVolume;
    propertyAOPA.mScope = kAudioDevicePropertyScopeOutput;
    
    AudioDeviceID outputDeviceID = [self getDefaultOutputDeviceID];
    
    if (outputDeviceID == kAudioObjectUnknown)
    {
        printf("Unknown device");
        return 0.0;
    }
    
    if (!AudioHardwareServiceHasProperty(outputDeviceID, &propertyAOPA))
    {
        printf("No volume returned for device 0x%0x", outputDeviceID);
        return 0.0;
    }
    
    status = AudioHardwareServiceGetPropertyData(outputDeviceID, &propertyAOPA, 0, NULL, (UInt32[]){sizeof(Float32)}, &outputVolume);
    
    if (status)
    {
        printf("No volume returned for device 0x%0x", outputDeviceID);
        return 0.0;
    }
    
    if (outputVolume < 0.0 || outputVolume > 1.0) return 0.0;
    
    return outputVolume;
}
//设置系统音量
+(void)setSystemVolumeValue:(Float32)newVolume {
    if (newVolume < 0.0 || newVolume > 1.0) {
        NSLog(@"Requested volume out of range (%.2f)", newVolume);
        return;
    }
    
    
    UInt32 propertySize = 0;
    OSStatus status = noErr;
    AudioObjectPropertyAddress propertyAOPA;
    propertyAOPA.mElement = kAudioObjectPropertyElementMaster;
    propertyAOPA.mScope = kAudioDevicePropertyScopeOutput;
    if (newVolume < 0.001) {
        NSLog(@"Requested mute");
        propertyAOPA.mSelector = kAudioDevicePropertyMute;
    }
    else {
        NSLog(@"Requested volume %.2f", newVolume);
        propertyAOPA.mSelector = kAudioHardwareServiceDeviceProperty_VirtualMasterVolume;
    }
    AudioDeviceID outputDeviceID = [self getDefaultOutputDeviceID];
    if (outputDeviceID == kAudioObjectUnknown) {
        NSLog(@"Unknown device"); return;
    }
    if (!AudioHardwareServiceHasProperty(outputDeviceID, &propertyAOPA)) {
        NSLog(@"Device 0x%0x does not support volume control", outputDeviceID);
        return;
    }
    Boolean canSetVolume = NO;
    status = AudioHardwareServiceIsPropertySettable(outputDeviceID, &propertyAOPA, &canSetVolume);
    if (status || canSetVolume == NO) {
        NSLog(@"Device 0x%0x does not support volume control", outputDeviceID);
        return;
    }
    if (propertyAOPA.mSelector == kAudioDevicePropertyMute) {
        propertySize = sizeof(UInt32);
        UInt32 mute = 1;
        status = AudioHardwareServiceSetPropertyData(outputDeviceID, &propertyAOPA, 0, NULL, propertySize, &mute);
    }
    else {
        propertySize = sizeof(Float32);
        status = AudioHardwareServiceSetPropertyData(outputDeviceID, &propertyAOPA, 0, NULL, propertySize, &newVolume);
        if (status) {
            NSLog(@"Unable to set volume for device 0x%0x", outputDeviceID);
        }
        // make sure we're not muted
        propertyAOPA.mSelector = kAudioDevicePropertyMute;
        propertySize = sizeof(UInt32);
        UInt32 mute = 0;
        if (!AudioHardwareServiceHasProperty(outputDeviceID, &propertyAOPA)) {
            NSLog(@"Device 0x%0x does not support muting", outputDeviceID);
            return;
        }
        Boolean canSetMute = NO;
        status = AudioHardwareServiceIsPropertySettable(outputDeviceID, &propertyAOPA, &canSetMute);
        if (status || !canSetMute) {
            NSLog(@"Device 0x%0x does not support muting", outputDeviceID);
            return;
        }
        status = AudioHardwareServiceSetPropertyData(outputDeviceID, &propertyAOPA, 0, NULL, propertySize, &mute);
    }
    if (status) {
        NSLog(@"Unable to set volume for device 0x%0x", outputDeviceID);
    }
}

@end

注意:

  • a.书写“@import AVFoundation;”来引入AVFoundation库支持获取设置系统音量’是必须!

  • b.会有许多提示API要弃用的警告!(但是目前还未找到 替代的API其他实现方法

    其中“'AudioHardwareServiceHasProperty' is deprecated: first deprecated in macOS 10.11 - no longer supported”有4个、“'AudioHardwareServiceGetPropertyData' is deprecated: first deprecated in macOS 10.11 - no longer supported”有2个、“'AudioHardwareServiceIsPropertySettable' is deprecated: first deprecated in macOS 10.11 - no longer supported”有2个、“'AudioHardwareServiceSetPropertyData' is deprecated: first deprecated in macOS 10.11 - no longer supported”有3个!

    'AudioHardwareServiceHasProperty' is deprecated: first deprecated in macOS 10.11 - no longer supported
    'AudioHardwareServiceGetPropertyData' is deprecated: first deprecated in macOS 10.11 - no longer supported
    'AudioHardwareServiceHasProperty' is deprecated: first deprecated in macOS 10.11 - no longer supported
    'AudioHardwareServiceGetPropertyData' is deprecated: first deprecated in macOS 10.11 - no longer supported
    'AudioHardwareServiceHasProperty' is deprecated: first deprecated in macOS 10.11 - no longer supported
    'AudioHardwareServiceIsPropertySettable' is deprecated: first deprecated in macOS 10.11 - no longer supported
    'AudioHardwareServiceSetPropertyData' is deprecated: first deprecated in macOS 10.11 - no longer supported
    'AudioHardwareServiceSetPropertyData' is deprecated: first deprecated in macOS 10.11 - no longer supported
    'AudioHardwareServiceHasProperty' is deprecated: first deprecated in macOS 10.11 - no longer supported
    'AudioHardwareServiceIsPropertySettable' is deprecated: first deprecated in macOS 10.11 - no longer supported
    'AudioHardwareServiceSetPropertyData' is deprecated: first deprecated in macOS 10.11 - no longer supported
    
    出现的警告



在Swift中操作OC类,需要进行桥接——引入头文件"MacAudioVolumeObject.h"

在桥接头文件中添加上""——"MacAudioVolumeObject.h"

之后在Swift代码中就可以使用操作该OC类(MacAudioVolumeObject)了:

在Swift中使用“设置系统音量”的方法

功能实现的代码书写:

override func viewDidLoad() {
    super.viewDidLoad()
    
    let slider = NSSlider(frame: NSMakeRect(100, 100, 200, 50))
    self.view .addSubview(slider)
    //设置背景色
    slider.wantsLayer = true
    slider.layer?.backgroundColor = NSColor.cyan.cgColor
    //minValue默认为0.0,maxValue默认为1.0
    print("minValue:\(slider.minValue), maxValue:\(slider.maxValue)")
    //添加操作的响应事件
    slider.target = self;   slider.action = #selector(sliderValueChange)
    
    //获取当前系统音量
    let sysVolume = MacAudioVolumeObject .getVolume()
    slider.floatValue = sysVolume//设置slider的初始值(音量)
    print("sysVolume:\(sysVolume),slider.floatValue:\(slider.floatValue)")
}
@objc func sliderValueChange(slider: NSSlider) {
    //设置当前系统音量
    MacAudioVolumeObject .setSystemVolumeValue(slider.floatValue)
    
}

效果
a.刚打开App后,通过.getVolume()方法获取当前系统音量大小(0.0~1.0),并设置给滑动器
(打印—sysVolume:0.23832849,slider.floatValue:0.23832849)
b.拖动滑动器时会通过.setSystemVolumeValue(slider.floatValue)方法设置 系统音量大小,顶部状态栏音量提示也会改变


注意:运行代码时,会有打印⚠️

2021-05-24 10:06:16.890878+0800 ControlMacAudioVolume[2558:62317] [plugin] AddInstanceForFactory: No factory registered for id <CFUUID 0x600000242180> F8BB1C28-BAE8-11D6-9C31-00039315CD46
2021-05-24 10:06:16.950842+0800 ControlMacAudioVolume[2558:62317]  HALC_ShellDriverPlugIn::Open: Can't get a pointer to the Open routine
2021-05-24 10:06:16.951538+0800 ControlMacAudioVolume[2558:62317]  HALC_ShellDriverPlugIn::Open: Can't get a pointer to the Open routine

以前写代码时就一直存在!到现在仍未找到解决方法!(已经解决的小伙伴可以交流一下~)


至此,macOS上系统音量控制的功能就实现了~

目前自己就只找到了这种方式,用了这么久一直不是很爽—使用了系统弃用API运行代码还有警告⚠️
之前使用了AVCaptureAudioChannelAVCaptureAudioPreviewOutput试试可不可实现,结果没有能实现!
(还有其他实现方式的小伙伴的话,希望可以交流一下~)








goyohol's essay

上一篇 下一篇

猜你喜欢

热点阅读