如何将系统卷与系统卷分开设置(iOS设备卷物理键)? [英] How to set app volume separately from system volume ( iOS device volume physical keys )?

查看:72
本文介绍了如何将系统卷与系统卷分开设置(iOS设备卷物理键)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们的应用程序可以在wifi扬声器上播放音乐。该应用程序的一个功能是通过按下音量+ /音量 - iPhone上的硬键来改变扬声器的音量。

Our app is able to play music on a wifi speaker. One of the features of the app is changing the volume of speaker through pressing volume + / volume - hard keys on the iPhone.

这背后的逻辑是获得音量值系统并将其发送给扬声器。

The logic behind this is getting the volume value of the system and send it to the speaker.

然而,问题是此功能会影响系统音量。在应用程序内部按音量键时是否还要避免调整系统音量?

However, the problem is that this function affects the system volume. Is there anyway to avoid adjusting the system volume when pressing the volume keys while inside the app?

这是我在每次按下时获取系统音量的代码:

This is the code that I used to get the system volume on every press:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqual:@"outputVolume"])
    {
        CGFloat phoneVolume = [[AVAudioSession sharedInstance] outputVolume];
        NSInteger volume = 100 * phoneVolume;

        [self onHardKeyVolumeChange:volume];
    }
}

谢谢。

推荐答案

这就是我所做的:


  1. 获取当前系统音量。

  2. 隐藏音量调整弹出视图。

  3. 添加观察者以了解系统音量的变化。

  4. 设置系统音量回到你从观察者那里收到的每一个回调中你得到的音量(步骤1)。

  1. Get the current system volume.
  2. Hide volume adjust popup view.
  3. Add observer for changes in system volume.
  4. Set the system volume back to the volume you got(at step 1) in every callbacks you received from the observer.

我会解释每一步细节。

第1步 - 获取当前系统容量

初始化代码卷:

- (void)initializeSystemVolume
{
    _originalSystemVolume = [[AVAudioSession sharedInstance] outputVolume];
    _currentSystemVolume = _originalSystemVolume;

    if(_currentSystemVolume == 0.0)
    {
        _currentSystemVolume = 0.0625;
    }

    else if(_currentSystemVolume == 1.0)
    {
        _currentSystemVolume = 0.9375;
    }

    [self setSystemVolume:_currentSystemVolume];
}

_originalSystemVolume - 这是系统的音量进入应用程序时。

_originalSystemVolume - This is the volume of the system when entering the app.

_currentSystemVolume - 这也可能与原始卷 BUT 相同改变了,而originalSystemVolume应保持不变。

_currentSystemVolume - This could also be the same as the original volume BUT this could be changed, while originalSystemVolume should stay the same.

从if else语句中可以看出,我将首先检查当前系统卷是否为最大值(1.0 )或最小值(0.0)。我为什么要这样做?

As you can see from the if else statement, I will check first if the current system volume is at the maximum value(1.0) or the minimum value(0.0). Why would I do this?

因为从我的实验中,我注意到只有在系统音量发生变化时才会进行音量键按下的回调。因此,如果当前系统音量处于其最小值(0.0),并且您仍按下音量 - 按钮。不会进行回调。然后你永远不会确定音量 - 在这种情况下按键状态。

Because from my experiments, I noticed that the callback of the volume key press would only be made only if the system volume has changed. So if the current system volume is at its minimum value(0.0), and you still pressed the volume - button. No callbacks would be made. Then you would never determine the volume - key press state in this case.

这就是为什么我需要将当前系统音量更改为更高音量(0.0625)如果它处于最大值,则它处于最小值或将其更改为较低的音量(0.9375),这样我们仍然可以从系统获得回调。现在,为什么0.0625和0.9375?

So that is why I need to change the current system volume to a higher volume(0.0625) if it is at its minimum or change it to a lower volume(0.9375) if it's at its maximum so that we will still be able to get callbacks from the system. Now, why 0.0625 and 0.9375?

嗯,实际上我只是想把它设置为最接近的值。
如果您注意到,iOS的音量分为16级,每级增加0.0625。 0.0是静音模式,1.0是峰值音量。

Well, actually I just want to set it to the closest possible value. If you would notice, the volume of iOS breaks down into 16 levels, and each level increments by 0.0625. 0.0 is silent mode and 1.0 is the peak volume.

步骤2 - 隐藏音量调整弹出视图

隐藏音量弹出窗口的代码:

Code for hiding the volume popup:

- (void)moveVolumeChangeNotifSliderOffTheScreen
{
    CGRect frame = CGRectMake(0, -100, 10, 0);
    MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:frame];
    [volumeView sizeToFit];
    [[[[UIApplication sharedApplication] windows] objectAtIndex:0] addSubview:volumeView];
}

由于我们不会影响系统音量,所以我们不应该显示弹出窗口也是如此。

Since we will not be affecting the system volume, then we shouldn't display the popup as well.

此代码的信用额转给另一个人。对不起,我忘记了我的位置,但我没有写。

Credit of this code goes to another person. I am sorry I forgot where I got this, but I didn't write it.

步骤3 - 添加观察者以了解系统容量的变化。

现在,我们应该在每次按键时监听系统音量的变化,然后我们可以使用回调返回的值来确定按下哪个音量键。

Now, we should listen for changes in the system volume with every key press, and then we can use the value returned by the callback to determine which volume key is pressed.

代码设置观察者:

- (void)setVolumeChangeObserver
{
    [self removeVolumeChangeObserver];

    [[AVAudioSession sharedInstance] setActive:YES error:nil];
    [[AVAudioSession sharedInstance] addObserver:self forKeyPath:@"outputVolume" options:0 context:nil];
}

移除观察者的代码:

- (void)removeVolumeChangeObserver
{
    @try
    {
        [[AVAudioSession sharedInstance] removeObserver:self forKeyPath:@"outputVolume"];
    }

    @catch(id anException)
    {

    }
}

回调代码:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqual:@"outputVolume"])
    {
        if([[AVAudioSession sharedInstance] outputVolume] < _currentSystemVolume)
        {
            NSLog(@"Volume key down");

            //your code when volume key down is pressed.
        }

        else if([[AVAudioSession sharedInstance] outputVolume] > _currentSystemVolume)
        {
            NSLog(@"Volume key up");

            //your code when volume key up is pressed.
        }

        [self removeVolumeChangeObserver];
        [self setSystemVolume:_currentSystemVolume];
        [self setVolumeChangeObserver];
    }
}

从代码中可以看出,我们用户按下按钮后的outputVolume并将其与我们前一段时间设置的_currentSystemVolume进行比较,我们可以确定是按下音量+还是按下音量 -

As can be seen from the code, we user the outputVolume upon key press and compare it with our _currentSystemVolume that we set awhile ago, we could determine whether volume + is pressed or volume - is pressed.

分析哪个键是按下,我们应该立即将系统音量设置回原来的音量,以便在我们的应用程序中按下音量按键不会影响系统音量。

After analyzing which key is pressed, we should immediately set the system volume back to what it was so that volume key press made within our app will not affect the system volume.

重要:在设置系统音量之前,必须先删除观察者。为什么?因为如果你不这样做,一旦你设置了系统卷,这个回调将再次发生,当发生这种情况时,将再次调用 setSystemVolume ,然后回调将再次进行,然后将再次调用 setSystemVolume ,然后反复调用...然后,您将在此处创建死锁。通过删除观察者,不会进行回调。

Important: You have to remove the observer first before you set the system volume. Why is that so? Because if you don't do that, once you set the system volume, this callback will be made again, and when that happens the setSystemVolume will be called once more, then callback will be made again, then your setSystemVolume will be called again, then over and over again... You will then create a deadlock on this. By removing the observer, no callbacks will be made.

第4步 - 设置系统音量

现在,我们如何设置系统音量呢?

Now, how do we set the system volume then?

设置系统音量的代码:

- (void)setSystemVolume:(CGFloat)volume
{
    if(_volumeView == nil)
    {
        _volumeView = [[SystemVolumeView alloc] init];
    }

    _volumeView.getVolumeSlider.value = volume;
}

_volumeView是我制作的类SystemVolumeView的一个实例,它扩展了MPVolumeView检索MPVolumeView的UISlider。 MPVolumeView是调整系统音量(媒体音量)时弹出的视图。

_volumeView is an instance of the class, SystemVolumeView, that I made, which extends MPVolumeView to retrieve the UISlider of MPVolumeView. MPVolumeView is the view that pops up when you adjust the volume of the system(media volume).

SystemVolumeView代码:

Code for SystemVolumeView:

SystemVolumeView.h

#import <MediaPlayer/MediaPlayer.h>

@interface SystemVolumeView : MPVolumeView

- (UISlider *)getVolumeSlider;

@end

SystemVolumeView.m

#import <AVFoundation/AVFoundation.h>

#import "SystemVolumeView.h"

@interface SystemVolumeView ()

@property UISlider *systemVolumeSlider;

@end

@implementation SystemVolumeView

- (UISlider *)getVolumeSlider
{
    if(_systemVolumeSlider != nil)
    {
        return _systemVolumeSlider;
    }

    self.showsRouteButton = false;
    self.showsVolumeSlider = false;
    self.hidden = true;

    for(UIView *subview in self.subviews)
    {
        if([subview isKindOfClass:[UISlider class]])
        {
            _systemVolumeSlider = (UISlider *)subview;
            _systemVolumeSlider.continuous = true;

            return _systemVolumeSlider;
        }
    }

    return nil;
}

@end

此代码的信用额度为链接中接受的答案。我刚把它翻译成了Objective-C。

Credit of this code goes to the accepted answer in this link. I just translated it to Objective-C.

从上面的代码中可以看出,你可以通过调用 getVolumeSlider.value来设置系统音量。 = yourDesiredVolume 。 yourDesiredVolume应该只有0 - 1的范围。

As can be seen from the above code, you can set the system volume by calling getVolumeSlider.value = yourDesiredVolume. yourDesiredVolume should only be of range 0 - 1.

好的,在完成所有这些之后,你应该知道它们是如何工作的。

Alright, after all of this, you should have an idea on how these works.

现在,您可能会注意到我们没有使用 _originalSystemVolume

Now, you might noticed we didn't use _originalSystemVolume.

这是什么是为了。想象一下,如果系统的音量最初设置为静音,那么我们会将其设置为更高的值以使一切正常工作吗?现在,一旦应用程序进入后台,我们应该将系统卷设置回原来的状态。在这种情况下,我们会在应用程序重新启动时执行此操作。

Here's what that was for. Imagine if the volume of the system is set to silent initially, then we would set it to a higher value to make everything work right? Now, once the app enters background, we should set the system volume back to what it was. In this case we would do this when app is resigning active.

- (void)applicationWillResignActive:(UIApplication *)application
{
    [self restoreSystemVolume];
}

恢复系统容量代码:

- (void)restoreSystemVolume
{
    [self setSystemVolume:_originalSystemVolume];
}

这是所有人。我希望有一天这个答案对你有很大的帮助。 :)

That's all folks. I hope this answer will be of great help to you someday. :)

感谢@Joris van Liempd iDeveloper。 来自他的链接帮助我实现了这一目标。

Thanks to @Joris van Liempd iDeveloper. This link from him helped me a lot on achieving this.

这篇关于如何将系统卷与系统卷分开设置(iOS设备卷物理键)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆