关于音量调节

版权所有,禁止匿名转载;禁止商业使用。

模块一

一.系统(铃声)音量,媒体音量,通话音量,静音键

(此处暂不提各软件的音量,下面讨论不涉及软件音量,因为各软件涉及到调用的问题,请看第四项)


1.      定义:

系统音量,指的是带有铃声的声音(设置-声音里面的所有提醒声音,包括闹钟,但闹钟比较特殊请看第二项)。具体为来电铃声,通知铃声,闹铃等。

媒体音量,iOS常指音乐,视频,主动播放类声音。包含部分软件内的声音等。

通话音量,当你通话,facetime时,调节音量键,即可调整通话音量。

以上三类音量,是相对独立控制的,不可交互调节。而且都会自动记忆调节量。


2.      特殊的是系统音量与媒体音量(关键在于:设置-声音-<用按钮调整>开关)

实例:

【关闭<用按钮调整>】:主屏幕调节音量键,显示的是音量(此处是指媒体音量),而系统(铃声)音量则必须在[设置-声音]中用控制条调节。

【打开<用按钮调整>】:主屏幕调节音量键,显示的是铃声(此处是指系统(铃声)音量,只能调到最低一格),而不是调节媒体音量,则媒体音量必须在主动播放类(音乐,视频,部分软件)之中调节音量键。所以有时候你明明一直按着音量减,打开程序的时候却还是很大声就是这个原因。

所以很迷糊,很绕是吧,没关系,关闭<用按钮调节>按钮,单独控制好系统铃声音量,想静音就直接拨静音键。主屏幕或锁屏调节音量键就是调节媒体音量(包括大部分软件音量)


3.      静音键不管什么?

静音键管的东西可多了(包括拍照声,嘿嘿**记得静音啊!!!),但是我们最好心里清楚它到底不管什么!防止拨开静音键却某些声音不被静音!

静音键不管闹钟,通话音量,媒体音量,所以拨了静音键放动作片或者高潮音乐时,你会被行注目礼的。

                   其他的静音键都管!




二.闹钟

         闹钟响还是不响?这是最大的问题了吧!

         闹钟调用的是系统(铃声)音量,但是闹钟是系统音量中唯一不受静音键控制的!却受制于<设置-音量>中的音量控制条!

         所以<用按钮调整>这一开关尤为重要!


         实例分析一下,

【打开<用按钮调整>】:当你在待机界面按音量键调低音量后,系统铃声就会随着减小,太小就会漏接电话,更有甚者会闹钟、提醒听不到耽误大事啊!

【关闭<用按钮调整>】:将设置-音量-音量控制条调节适当,不论在哪调节音量键都不会改变闹钟和铃声的音量大小,闹铃会很安全的。

         注意,iPhone以前和现在都不支持关机闹铃!千万不要养成睡觉关机的“好习惯”(BTW:以前不支持关机充电,现在支持关机充电)




三.耳机音量与手机外放


1.       耳机音量控制最简便,不论什么声音,例如铃声什么的,都会平衡成你当前调节的耳机音量,不用担心被突如其来的铃声撕裂耳膜。

2.       非静音时当有系统提醒时,耳机会响,手机外放也会响,其他声音只走耳机。

静音时,系统提醒耳机不会响,手机也不会响。但你听音乐、看视频、玩游戏的声音还是会走耳机传出来。

一句话,插上耳机,打开静音按钮,手机就绝对不会出声音了。关闭静音按钮,只有系统提醒会走手机放出,其他声音一律不会走手机。放心用你的耳机!(你懂的,就算播放某视频或音乐,意外拔出耳机,也不会泄露声音,视频或音乐会自动暂停。)




四.各软件音量!(最难搞的地方)


软件分很多类型,游戏,音乐,阅读等等一堆。它们调用的到底是系统音量还是媒体音量呢?很不好判断,所以有时候静音键也不一定都管用。

例如:XX音乐软件,它肯定调用媒体音量啊!不对!它的一部分可能是调用媒体音量!软件内播放视频音乐,是调用媒体音量!软件内新消息提醒有可能调用系统(铃声)音量!

所以如果想弄懂,很麻烦,要一个一个软件自己去习惯和尝试了。


上面这句是废话,下面这些才是关键:

(手机外放)彻底静音一个的方法:

1.      【关闭<用按钮调整>】,打开静音键,主屏幕或锁定屏幕调低音量至静音即可!

2.      【打开<用按钮调整>】,打开静音键,先播放音乐然后把音量调低至静音(或直接上拉控制中心,调低音量控制条)即可!

3.      插入耳机,打开静音键!(只有耳机会有声音哦)

赶着下班,差不多写完了,也没怎么检查,如有问题我再跟大家探讨,下一次写什么大家来决定吧!

最近项目有个功能需要用到监听音量实体键,并能够通过滑动应用内的UISlider调整系统的音量,其中遇到不少问题,所以记录下这个学习过程。

尽管 AVPlayer AVPAudiolayer 这些类提供了音量调节功能,但这些音量控制属于App级别的控制。好处就是音量调节独立于系统音量,调节大小时不会影响系统音量。但有时候我们可能希望修改系统音量,以免在调节声音的时候,如果系统音量过小,App调节音量效果不明显。

模块二

一、监听手机实体音量按键

  • 和监听键盘弹出类似的,Apple提供了一个通知给我们,只要在合适的地方添加对这个通知的监听即可。

- (void)registeNotification{

    //1.注册监听系统音量变化,记得在适当的地方移除监听

    [[NSNotificationCenter defaultCenter] addObserver:self

                                  selector:@selector(volumeChanged:) name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil];

      // UIApplication 开始响应远程的控制,必须添加,不然没效果

      [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

}

- (void)volumeChanged:(NSNotification *)notification{

    //2.获取到当前音量

    float volume = [[[notification userInfo] objectForKey:@"AVSystemController_AudioVolumeNotificationParameter"] floatValue];

    //do something here

}

- (void) removeNotification{

    //3.移除监听

    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil];

}

  //结束远程的控制

  [[UIApplication sharedApplication] endReceivingRemoteControlEvents];

虽然有效果,但是问题来了

1.实体键按下的时候,会出现系统的"铃声",而我想要显示"音量"

uyqyuaV.png!web.png

这个时候可以添加一句代码,即可让在这个页面时,按下音量实体键显示 音量 ,而不是铃声

//使音量控制实体键响应音量而不是铃声

[[AVAudioSession sharedInstance] setActive:YES error:NULL];

FnmimeV.png!web.png

2.出现了"音量",但是因锁屏、进入后台等原因 ResignActive 重新激活后,又显示了"铃声"而不是"音量"

这是因为程序进入后台后,上述一行代码 [AVAudioSession sharedInstance] 又不再是 Active 状态,所以需要在 AppDelegate.m 里面重新设置,这样即可一直响应音量了,比如:

AppDelegate.m

- (void)applicationWillEnterForeground:(UIApplication *)application {

      //使程序重新激活后,对音量实体键响应为音量而不是铃声

      [[AVAudioSession sharedInstance] setActive:YES error:NULL];

}

3.我不想出现"音量"

这个时候就需要用到 MPVolumeView ,它不仅可以不显示音量,还可以修改设置手机音量。

这个方法是苹果官方推荐的方法。MPVolumeView Media Player Framework 中的一个UI组件,直接包含了对系统音量和Airplay设备的音频镜像路由的控制功能。其中包含一个 MPVolumeSlider subview用来控制音量。这个 MPVolumeSlider 是一个私有类,我们无法手动创建此类,但这个类是UISlider的子类。MPVolumeView的使用很简单,只需要将其加入到一个父视图中,给予父视图合适的大小,再创建 MPVolumeView 示例,将其加入到父视图中即可, 苹果官方的文档 中有示例代码可以参考。

  • 这个方法的缺点如下:
    • UI可定制的的程度低。 MPVolumeView只提供了有限的几个方法来定制其中的SliderRoute Button的样式,而且基本上只能靠换图片解决。如果你想把Slider操作换成Button或者其他的UI组件,那是不可能的。
    • 没有额外的音量控制API 目前为止没有发现iOS的公开API中有可以直接操作系统音量的,所以修改系统音量只能使用这个UI组件。如果还想给UI加入手势操作来控制音量,这种直接使用MPVolumeView 是做不到的,那么有没有什么方法可以绕过这限制呢?办法还是有的。
  • 实际上MPVolumeView没有提供任何接口来调节是否需要显示系统音量提示。但是我们发现一点:当MPVolumeView处在当前视图的层级之中时,系统就不会显示音量提示。那么事情好办了,我们只要确保两点:
    • MPVolumeView视图处在屏幕上看不见的地方,比如某个不透明视图的下方,或者本视图的非可见区域,一个常见的做法就是把该视图的frame设置为区域以外的地方,比如 volumeView.frame = CGRectMake(-1000, -100, 100, 100);
    • 确保MPVolumeView视图的 hidden 属性值为 NO 。因为当hiddenYES时,同样会弹出提示。

于是想要隐藏"音量提示框"就可以通过添加以下代码实现:

//隐藏"音量提示框"

//注意使用之前需要添加`MediaPlayer.framework`

MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:CGRectMake(-100, -100, 100, 100)];

volumeView.hidden = NO;

[self.view addSubview:volumeView];

代码实现调节系统音量,不通过实体按键

上面我们提到了MPVolumeView这个组件中,有一个subview来控制音量,即 MPVolumeSlider 。于是我们可以通过遍历 MPVolumeView 实例的subviews来得到MPVolumeSlider的实例,从而通过这个UI组件来操作系统音量。

  • 步骤如下:
    • 1.通过创建一个MPVolumeView
    • 2.遍历找出MPVolumeSlider的实例
    • 3.可以通过 volumeSlider.value 这个属性来获取当前的系统音量。
    • 4.这个实例提供 setValue:animated: 方法来设置系统音量
    • 5.添加一个自定义的视图比如一个slider,通过这个视图来改变系统音量

具体的代码如下:

- (void)viewDidLoad {

    [super viewDidLoad];

  //不显示铃声,显示音量

    [[AVAudioSession sharedInstance] setActive:YES error:NULL];

    //1. 获得 MPVolumeView 实例,

    MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:CGRectMake(-100, -100, 100, 100)];

    //volumeView.hidden = NO;

    //[self.view addSubview:volumeView]; //添加后不显示音量

    volumeViewSlider = nil;

    //2. 遍历MPVolumeViewsubViews得到MPVolumeSlider

    for (UIView *view in [volumeView subviews]){

        if ([view.class.description isEqualToString:@"MPVolumeSlider"]){

            volumeViewSlider = (UISlider*)view;

            break;

        }

    }

    //3.获取系统音量

    float systemVolume = volumeViewSlider.value;

    //4.添加一个全局的 slider,滑动时同步改变系统音量

    VolSlider = [[UISlider alloc] initWithFrame:CGRectMake(30, 200, 300, 20)];

    VolSlider.value = systemVolume;  //初始值

    [VolSlider setMinimumValue:0.0]; //最小值

    [VolSlider setMaximumValue:1.0]; //最大值

    [VolSlider addTarget:self action:@selector(sliderValueChange:) forControlEvents:UIControlEventValueChanged]; //添加事件

    [self.view addSubview:VolSlider];

    //注册监听实体键按下事件

    [self registeNotification];

}

//

//VolSlider滑动事件

- (void)sliderValueChange:(UISlider *)slider{

    //得到当前用户设置的value

    float value = slider.value;

    //改变系统音量大小,默认音量大小从 0.0 - 1.0

    [volumeViewSlider setValue:value animated:NO];

    //使setValue立即生效,

    [volumeViewSlider sendActionsForControlEvents:UIControlEventTouchUpInside];

}

//

//监听音量实体键按下后,响应事件

- (void)volumeChanged:(NSNotification *)notification{

    //获取到当前系统音量

    float volume = [[[notification userInfo] objectForKey:@"AVSystemController_AudioVolumeNotificationParameter"] floatValue];

    //同步设置自定义视图的值

  [VolSlider setValue:volume animated:YES];

}

设置后即可使 VolSlider 与系统的音量提示框同步了,效果如下:

eUFnyqn.png!web.png

模块三方法1

     applicationDidFinishLaunching函数里添加

      [[NSNotificationCenter defaultCenter] addObserver:self

                                             selector:@selector(volumeChanged:)

                                             name:@"AVSystemController_SystemVolumeDidChangeNotification"

                                             object:nil];


  - (void)volumeChanged:(NSNotification *)notification

{

    float volume =

    [[[notification userInfo]

      objectForKey:@"AVSystemController_AudioVolumeNotificationParameter"]

     floatValue];

    

    DDLogVerbose(@"current volume = %f", volume);   

}


   弊端:当app进入后天后,依然会监听到volume的变化


2. AudioSession 添加volume变化的 listener, 可以放在startAudioSession函数里

    //add a listener for Outputvolume

    AudioSessionAddPropertyListener(kAudioSessionProperty_CurrentHardwareOutputVolume ,

                                    volumeListenerCallback,

                                    self

                                    );



void volumeListenerCallback (

                             void                      *inClientData,

                             AudioSessionPropertyID    inID,

                             UInt32                    inDataSize,

                             const void                *inData

                             ){

    const float *volumePointer = inData;

    float volume = *volumePointer;

    NSLog(@"volumeListenerCallback %f", volume);

}


3. 获取当前的volume

     float volume = 0.0;

    UInt32 dataSize = sizeof(float);

    OSStatus status = AudioSessionGetProperty (kAudioSessionProperty_CurrentHardwareOutputVolume,

                             &dataSize,

                             &volume);






0 0