|
| 1 | +# 2018.01 |
| 2 | + |
| 3 | +为什么音频播放器突然没声音了呢? |
| 4 | +-------- |
| 5 | + |
| 6 | +做音频的同学可能都会遇到播放的音频突然没声音的情况,遇到这种情况后,一般控制台会抛出下面的错误: |
| 7 | + |
| 8 | +```objc |
| 9 | +[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.` |
| 10 | +``` |
| 11 | + |
| 12 | +遇到这个错误,会导致音频不能正常播放的情况。出现这种情况的主要原因当你设置 |
| 13 | + |
| 14 | +```objc |
| 15 | +[[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil]; |
| 16 | +``` |
| 17 | +
|
| 18 | +时还有某些操作占用了 `AVAudioSession` 权限,必须暂停或停止对 `AVAudioSession` 的使用。比如使用 `AVAudioPlayer` 播放某一音频时,此时音频正在播放,直接设置 `AVAudioSession` 的 `active` 为 `NO`,就会报上面提到的错误。而正确的做法是先暂停播放,再设置 `AVAudioSession` 的 `active` 为 `NO`。其正确的做法像下面代码所示,这样的好处是,当遇到设置失败后可以第一时间知道出错的时间点。 |
| 19 | +
|
| 20 | +```objc |
| 21 | +NSError *error; |
| 22 | +BOOL isSuccess = [[AVAudioSession sharedInstance] setActive:active withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error]; |
| 23 | +if (isSuccess) { |
| 24 | + NSLog(@"恭喜你成功设置"); |
| 25 | +} else { |
| 26 | + NSLog(@"设置失败"); |
| 27 | +} |
| 28 | +``` |
| 29 | + |
| 30 | +当然如果应用中有多个地方使用 `AVAudioSession`,建议项目中统一处理 `AVAudioSession` 的 `active`,这样避免出现错误,一旦出现错误,调试起来就非常费劲。 |
| 31 | + |
| 32 | +iOS 中音量控制解惑 |
| 33 | +-------- |
| 34 | + |
| 35 | +iOS 中音量中其实也有好多小窍门,这个小集帮你解惑。iOS 中主要有2个地方可以控制音量,一个是系统音量,用户主动按音量键,调整音量,这种方式会显示系统音量提示框;另一个是播放器的音量,比如通过 `AVAudioPlayer` 调整音量,这种不会显示系统提示音量框。 |
| 36 | + |
| 37 | +### 如何调节音量时不显示系统音量提示框 |
| 38 | + |
| 39 | +主要原理就是获取系统音量 `View`,并把它让用户不可见。但注意一点,你不能把 `MPVolumeView` 的 `hidden` 属性设置为 `YES`,这样导致的结果是用户调整音量时任然会显示系统音量提示框,如下代码所示。 |
| 40 | + |
| 41 | +``` |
| 42 | +_volumeView = [[MPVolumeView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)]; |
| 43 | +_volumeView.backgroundColor = [UIColor yellowColor]; |
| 44 | +
|
| 45 | +// 如果设置了 Hidden 为 YES,那么修改音量时会弹出系统音量框 |
| 46 | +_volumeView.hidden = NO; |
| 47 | +_volumeView.alpha = 0.01; |
| 48 | +for (UIView *view in [_volumeView subviews]){ |
| 49 | +if ([view.class.description isEqualToString:@"MPVolumeSlider"]){ |
| 50 | + self.volumeSlider = (UISlider*)view; |
| 51 | + break; |
| 52 | + } |
| 53 | +} |
| 54 | +[self.view addSubview:_volumeView]; |
| 55 | +``` |
| 56 | + |
| 57 | +### 获取系统音量 |
| 58 | + |
| 59 | +方法一:通过 `self.volumeSlider` 获取 |
| 60 | + |
| 61 | +如果想获取系统音量,可以通过第一种方式,`self.volumeSlider.value` 来获取,但是你发现第一次为 0,这很纠结,这样导致的结果就是获取的系统音量不准确。这是因为初始 `MPVolumeView` 时,`volumeSlider.value` 还没有赋值,如下图所示: |
| 62 | + |
| 63 | + |
| 64 | + |
| 65 | +可以发现,音量是后来通过 `[MPVolumeController updateVolumeValue]` 来更新的。所以我们可以通过监听 `self.volumeSlide` 值改变时的事件,达到获取系统音量的目的。 |
| 66 | + |
| 67 | +```objc |
| 68 | +[self.volumeSlider addTarget:self action:@selector(sliderValueDidChange:) forControlEvents:UIControlEventValueChanged]; |
| 69 | +``` |
| 70 | +
|
| 71 | +方法二:通过 `AVAudioSession` 获取 |
| 72 | +
|
| 73 | +```objc |
| 74 | +[[AVAudioSession sharedInstance] outputVolume]; |
| 75 | +``` |
| 76 | + |
| 77 | +这种方法直接了当。 |
| 78 | + |
| 79 | +### 自定义音量控件 |
| 80 | + |
| 81 | +如果想自定义音量控件,可以监听音量的变化,并且通过第一种方法隐藏系统音量提示框。通过监听通知,达到监听音量变化的效果。 |
| 82 | + |
| 83 | +### 监听音量变化 |
| 84 | + |
| 85 | +监听音量变化,通过监听通知 |
| 86 | + |
| 87 | +```objc |
| 88 | +AVSystemController_SystemVolumeDidChangeNotification |
| 89 | + |
| 90 | +[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(volumeChanged:) name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil]; |
| 91 | +``` |
| 92 | +
|
| 93 | +最终结果 `AVSystemController_AudioVolumeNotificationParameter` 表示音量的值,这里需要注意的是 `"AVSystemController_AudioVolumeChangeReasonNotificationParameter" = ExplicitVolumeChange;` 这个值,它会由于不同的场景,有不同的值。`ExplicitVolumeChange` 是用户点击音量按钮,`CategoryChange` 是用户按 `home` 键调起 `Siri`,`RouteChange` 这个时路线修改(不太清楚,什么情况下触发的)。 |
| 94 | +
|
| 95 | +```objc |
| 96 | +AVSystemController_SystemVolumeDidChangeNotification; object = <AVSystemController: 0x1c4001dc0>; userInfo = { |
| 97 | + "AVSystemController_AudioCategoryNotificationParameter" = "Audio/Video"; |
| 98 | + "AVSystemController_AudioVolumeChangeReasonNotificationParameter" = ExplicitVolumeChange; |
| 99 | + "AVSystemController_AudioVolumeNotificationParameter" = "0.5625"; |
| 100 | + "AVSystemController_UserVolumeAboveEUVolumeLimitNotificationParameter" = 0; |
| 101 | +}} |
| 102 | +``` |
| 103 | + |
| 104 | +### 注意点 |
| 105 | + |
| 106 | +如果通过代码修改了 `self.volumeSlide` 的 `value`,那么会显示出系统音量框,如果你发现某个页面突然蹦出一个系统音量框,原因大多数是你修改了这个值。 |
| 107 | + |
| 108 | + |
| 109 | + |
0 commit comments