如何在iOS上获取音频音量级别和音量更改通知?

2020/12/01 00:32 · ios ·  · 0评论

我正在编写一个非常简单的应用程序,该应用程序在按下按钮时会发出声音。由于在将设备设置为静音时该按钮没有多大意义,因此我想在设备的音量为零时禁用它。(然后在再次调高音量时重新启用它。)

我正在寻找一种可行的(和AppStore安全的)方法来检测当前的音量设置,并在音量级别更改时获得通知/回调。不想更改音量设置。

所有这一切都在ViewController使用上述按钮的地方实现我已经使用运行iOS 4.0.1和4.0.2的iPhone 4以及运行4.0.1的iPhone 3G对此进行了测试。使用llvm 1.5的iOS SDK 4.0.2构建。(使用gcc或llvm-gcc不会有任何改善。)在构建过程中,无论采用哪种方式都没有问题,也没有错误或警告。静态分析仪也很高兴。

到目前为止,这是我尝试过的一切,但都没有成功。

按照Apple的音频服务文档,我应该AudioSessionAddPropertyListener为其注册一个kAudioSessionProperty_CurrentHardwareOutputVolume这样的文件:

// Registering for Volume Change notifications
AudioSessionInitialize(NULL, NULL, NULL, NULL);
returnvalue = AudioSessionAddPropertyListener (

kAudioSessionProperty_CurrentHardwareOutputVolume ,
      audioVolumeChangeListenerCallback,
      self
);

returnvalue0,这表示注册回调有效。

令人遗憾的是,audioVolumeChangeListenerCallback当我按下设备上的音量按钮,耳机咔嗒声或拨动静音开关时,我再也无法回调函数

当使用完全相同的代码进行注册时kAudioSessionProperty_AudioRouteChange(在WWDC视频,开发人员文档以及互连网上的许多站点上用作类似的示例项目)时,实际上在更改音频路由时确实收到回调(通过插入/断开音频耳机或设备对接)。

名为Doug的用户打开了一个名为“音量已达到最大值”的iPhone音量已更改事件的线程,在该线程中,他声称已成功使用此方法(除非音量实际上未更改,因为音量已设置为最大值)。不过,它对我不起作用。

我尝试过的另一种方法是NSNotificationCenter像这样注册

// sharedAVSystemController 
AudioSessionInitialize(NULL, NULL, NULL, NULL);
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
                                         selector:@selector(volumeChanged:) 
                                             name:@"AVSystemController_SystemVolumeDidChangeNotification" 
                                           object:nil];

这应该volumeChanged将任何SystemVolume更改通知我的方法但实际上并没有这样做。

由于普遍的信念告诉我,如果一个人为完成可可而努力工作,那是在做根本上是错误的事情,那么我希望在这里会错过一些事情。很难相信没有简单的方法获得当前的音量水平,但是我一直无法使用Apple的文档,示例代码,Google,Apple Developer Forum或观看WWDC 2010视频找到一个。

您是否有可能为volumeChanged:方法签名错误?这对我有用,转储到我的appdelegate中:

- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [[NSNotificationCenter defaultCenter]
     addObserver:self
     selector:@selector(volumeChanged:)
     name:@"AVSystemController_SystemVolumeDidChangeNotification"
     object:nil];
}

- (void)volumeChanged:(NSNotification *)notification
{
    float volume =
    [[[notification userInfo]
      objectForKey:@"AVSystemController_AudioVolumeNotificationParameter"]
     floatValue];

    // Do stuff with volume
}

每次按下按钮时,我的volumeChanged:方法都会被点击,即使结果音量没有改变(因为它已经达到max / min)。

AudioSession自iOS 7起,此处一些答案使用API已被弃用。它已由取代AVAudioSession,它公开outputVolume了系统范围输出量属性。如文档中指出的,使用KVO可以在音量变化时接收通知,可以观察到这一点:

值在0.0到1.0之间,其中0.0表示最小体积,而1.0表示最大体积。

系统范围的输出量只能由用户直接设置;要在您的应用中提供音量控制,请使用MPVolumeView类。

您可以通过键值观察来观察对此属性值的更改。

您需要确保您应用的音频会话处于活动状态,才能正常工作:

let audioSession = AVAudioSession.sharedInstance()
do {
    try audioSession.setActive(true)
    startObservingVolumeChanges()
} catch {
    print(“Failed to activate audio session")
}

因此,如果您需要查询的是当前系统卷:

let volume = audioSession.outputVolume

或者我们可以收到如下更改通知:

private struct Observation {
    static let VolumeKey = "outputVolume"
    static var Context = 0

}

func startObservingVolumeChanges() {
    audioSession.addObserver(self, forKeyPath: Observation.VolumeKey, options: [.Initial, .New], context: &Observation.Context)
}

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
    if context == &Observation.Context {
        if keyPath == Observation.VolumeKey, let volume = (change?[NSKeyValueChangeNewKey] as? NSNumber)?.floatValue {
            // `volume` contains the new system output volume...
            print("Volume: \(volume)")
        }
    } else {
        super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
    }
}

不要忘记在释放之前停止观察:

func stopObservingVolumeChanges() {
    audioSession.removeObserver(self, forKeyPath: Observation.VolumeKey, context: &Observation.Context)
}
-(float) getVolumeLevel
{
    MPVolumeView *slide = [MPVolumeView new];
    UISlider *volumeViewSlider;

    for (UIView *view in [slide subviews]){
        if ([[[view class] description] isEqualToString:@"MPVolumeSlider"]) {
            volumeViewSlider = (UISlider *) view;
        }
    }

    float val = [volumeViewSlider value];
    [slide release];

    return val;
}

那应该给您当前音量。1是最大音量,0是无音量。注意:无需显示任何UI元素即可运行。还要注意,当前的音量级别是相对于耳机或扬声器的(这意味着两个音量级别是不同的,这可以让您使用设备当前使用的任何音量。这不会回答您有关接收音量变化通知的问题。

您是否使用AudioSessionSetActive启动了音频会话

使用AVAudioSession补充Stuart的答案,以说明Swift 3中的一些更改。我希望代码能够清楚说明每个组件的位置。

override func viewWillAppear(_ animated: Bool) {
    listenVolumeButton()
}

func listenVolumeButton(){
   let audioSession = AVAudioSession.sharedInstance()
   do{
       try audioSession.setActive(true)
       let vol = audioSession.outputVolume
       print(vol.description) //gets initial volume
     }
   catch{
       print("Error info: \(error)")
   }
   audioSession.addObserver(self, forKeyPath: "outputVolume", options: 
   NSKeyValueObservingOptions.new, context: nil)
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == "outputVolume"{
        let volume = (change?[NSKeyValueChangeKey.newKey] as 
        NSNumber)?.floatValue
        print("volume " + volume!.description)
    }
}

 override func viewWillDisappear(_ animated: Bool) {
     audioSession.removeObserver(self, forKeyPath: "outputVolume")
 }

Swift 3版本的Stuart的出色答案:

let audioSession = AVAudioSession.sharedInstance()

do {
    try audioSession.setActive(true)
    startObservingVolumeChanges()
} 
catch {
    print("Failed to activate audio session")
}

let volume = audioSession.outputVolume

private struct Observation {
    static let VolumeKey = "outputVolume"
    static var Context = 0
}

func startObservingVolumeChanges() {
    audioSession.addObserver(self, forKeyPath: Observation.VolumeKey, options: [.Initial, .New], context: &Observation.Context)
}

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
    if context == &Observation.Context {
        if keyPath == Observation.VolumeKey, let volume = (change?[NSKeyValueChangeNewKey] as? NSNumber)?.floatValue {
            // `volume` contains the new system output volume...
            print("Volume: \(volume)")
        }
    } else {
        super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
    }
}

我认为这取决于其他实现。例如,如果使用滑块控制音量,则可以执行检查操作;UIControlEventValueChanged如果值为0,则可以将按钮设置为隐藏或禁用。

就像是:

[MusicsliderCtl addTarget:self action:@selector(checkZeroVolume:)forControlEvents:UIControlEventValueChanged];

checkZeroVolume由于可以在更改任何体积后触发它,因此void可以对实际体积进行比较。

斯威夫特4

func startObservingVolumeChanges() {
    avAudioSession.addObserver(self, forKeyPath: Observation.VolumeKey, options: [.initial, .new], context: &Observation.Context)
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if context == &Observation.Context {
        if keyPath == Observation.VolumeKey, let volume = (change?[NSKeyValueChangeKey.newKey] as? NSNumber)?.floatValue {
            print("\(logClassName): Volume: \(volume)")
        }
    } else {
        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
    }
}

func stopObservingVolumeChanges() {
    avAudioSession.removeObserver(self, forKeyPath: Observation.VolumeKey, context: &Observation.Context)
}

然后你打电话

var avAudioSession = AVAudioSession.sharedInstance()
try? avAudioSession.setActive(true)
startObservingVolumeChanges()

Swift 5 / iOS 13

在我的测试中,我发现与系统卷交互的最可靠方法是MPVolumeView在每个操作中都使用。您已经需要在视图层次结构中的某个位置放置此视图,以使系统隐藏音量更改HUD。

在安装过程中(可能在内部)viewDidLoad(),创建您的MPVolumeView屏幕(如果您不想实际使用系统提供的控件,请在屏幕外):

let systemVolumeView = MPVolumeView(frame: CGRect(x: -CGFloat.greatestFiniteMagnitude, y: 0, width: 0, height: 0))
myContainerView.addSubview(systemVolumeView)
self.systemVolumeSlider = systemVolumeView.subviews.first(where:{ $0 is UISlider }) as? UISlider

获取设置音量:

var volumeLevel:Float {
    get {
        return self.systemVolumeSlider.value
    }
    set {
        self.systemVolumeSlider.value = newValue
    }
}

观察音量的变化(包括通过硬件按钮):

self.systemVolumeSlider.addTarget(self, action: #selector(volumeDidChange), for: .valueChanged)

@objc func volumeDidChange() {
    // Handle volume change
}

进入设置->声音,然后选中“使用按钮更改”。如果关闭,则按音量按钮时系统音量不会更改。也许这就是为什么您没有得到通知的原因。

本文地址:http://ios.askforanswer.com/ruhezaiiosshanghuoquyinpinyinliangjibieheyinlianggenggaitongzhi.html
文章标签: ,   ,   ,   ,  
版权声明:本文为原创文章,版权归 admin 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!