Skip to content

2018.01

Minya edited this page Jan 8, 2018 · 4 revisions

为什么音频播放器突然没声音了呢?

做音频的同学可能都会遇到播放的音频突然没声音的情况,遇到这种情况后,一般控制台会抛出下面的错误:

[AVAudioSession setActive:withOptions:error:]: Deactivating an audio session that has running I/O. All I/O should be stopped or paused prior to deactivating the audio session.

遇到这个错误,会导致音频不能正常播放的情况。出现这种情况的主要原因当你设置

[[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];

时还有某些操作占用了 AVAudioSession 权限,必须暂停或停止对 AVAudioSession 的使用。比如使用 AVAudioPlayer 播放某一音频时,此时音频正在播放,直接设置 AVAudioSessionactiveNO,就会报上面提到的错误。而正确的做法是先暂停播放,再设置 AVAudioSessionactiveNO。其正确的做法像下面代码所示,这样的好处是,当遇到设置失败后可以第一时间知道出错的时间点。

NSError *error;
BOOL isSuccess = [[AVAudioSession sharedInstance] setActive:active withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error];
if (isSuccess) {
   NSLog(@"恭喜你成功设置");
} else {
   NSLog(@"设置失败");
}

当然如果应用中有多个地方使用 AVAudioSession,建议项目中统一处理 AVAudioSessionactive,这样避免出现错误,一旦出现错误,调试起来就非常费劲。

iOS 中音量控制解惑

iOS 中音量中其实也有好多小窍门,这个小集帮你解惑。iOS 中主要有2个地方可以控制音量,一个是系统音量,用户主动按音量键,调整音量,这种方式会显示系统音量提示框;另一个是播放器的音量,比如通过 AVAudioPlayer 调整音量,这种不会显示系统提示音量框。

如何调节音量时不显示系统音量提示框

主要原理就是获取系统音量 View,并把它让用户不可见。但注意一点,你不能把 MPVolumeViewhidden 属性设置为 YES,这样导致的结果是用户调整音量时任然会显示系统音量提示框,如下代码所示。

_volumeView = [[MPVolumeView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
_volumeView.backgroundColor = [UIColor yellowColor];

// 如果设置了 Hidden 为 YES,那么修改音量时会弹出系统音量框
_volumeView.hidden = NO;
_volumeView.alpha = 0.01;
for (UIView *view in [_volumeView subviews]){
if ([view.class.description isEqualToString:@"MPVolumeSlider"]){
    self.volumeSlider = (UISlider*)view;
    break;
   }
}
[self.view addSubview:_volumeView];

获取系统音量

方法一:通过 self.volumeSlider 获取

如果想获取系统音量,可以通过第一种方式,self.volumeSlider.value 来获取,但是你发现第一次为 0,这很纠结,这样导致的结果就是获取的系统音量不准确。这是因为初始 MPVolumeView 时,volumeSlider.value 还没有赋值,如下图所示:

可以发现,音量是后来通过 [MPVolumeController updateVolumeValue] 来更新的。所以我们可以通过监听 self.volumeSlide 值改变时的事件,达到获取系统音量的目的。

[self.volumeSlider addTarget:self action:@selector(sliderValueDidChange:) forControlEvents:UIControlEventValueChanged];

方法二:通过 AVAudioSession 获取

[[AVAudioSession sharedInstance] outputVolume];

这种方法直接了当。

自定义音量控件

如果想自定义音量控件,可以监听音量的变化,并且通过第一种方法隐藏系统音量提示框。通过监听通知,达到监听音量变化的效果。

监听音量变化

监听音量变化,通过监听通知

AVSystemController_SystemVolumeDidChangeNotification

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(volumeChanged:) name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil];

最终结果 AVSystemController_AudioVolumeNotificationParameter 表示音量的值,这里需要注意的是 "AVSystemController_AudioVolumeChangeReasonNotificationParameter" = ExplicitVolumeChange; 这个值,它会由于不同的场景,有不同的值。ExplicitVolumeChange 是用户点击音量按钮,CategoryChange 是用户按 home 键调起 SiriRouteChange 这个时路线修改(不太清楚,什么情况下触发的)。

AVSystemController_SystemVolumeDidChangeNotification; object = <AVSystemController: 0x1c4001dc0>; userInfo = {
    "AVSystemController_AudioCategoryNotificationParameter" = "Audio/Video";
    "AVSystemController_AudioVolumeChangeReasonNotificationParameter" = ExplicitVolumeChange;
    "AVSystemController_AudioVolumeNotificationParameter" = "0.5625";
    "AVSystemController_UserVolumeAboveEUVolumeLimitNotificationParameter" = 0;
}}

注意点

如果通过代码修改了 self.volumeSlidevalue,那么会显示出系统音量框,如果你发现某个页面突然蹦出一个系统音量框,原因大多数是你修改了这个值。

小集

Clone this wiki locally