[AVAudioSession setActive:withOptions:error:]: Deactivating an audio session that has running I/O...

原因:

在AVAudioPlayer正在播放的时候去设置了AVAudioSession的active为NO,就会出现这个错误。

场景:

AVAudioPlayer播放 -> 百度TTS播报 -> AVAudioPlayer播放 -> 百度TTS播报 ......

AVAudioPlayer和百度TTS交替循环播放时,在百度TTS播报完成后百度TTS SDK会去设置 [[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];,并且这个设置是在子线程异步执行的,也就是说在播报成功的回调后才去设置AVAudioSession的active为NO,而我是在播报成功的回调中调用AVAudioPlayer播放的。这时候就造成了AVAudioPlayer正在播放的时候去设置了AVAudioSession的active为NO,然后就出现了上面的错误。

现象:

  1. AVAudioPlayer已经开始播放时去设置AVAudioSession的active为NO,只是会报上面的错误,AVAudioPlayerDelegate的方法都会正常回调。

  2. AVAudioPlayer刚开始播放时去设置AVAudioSession的active为NO,AVAudioPlayerDelegate的方法不会回调。

解决方法:

现在的解决办法是hook了AVAudioSession的setActive:withOptions:error:方法,然后判断AVAudioPlayer是否在播放,如果在播放则active设置成YES,如果没有在播放,则设置成NO。

@implementation AVAudioSession (LBYAudioSession)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [self class];
        
        SEL originalSEL = @selector(setActive:withOptions:error:);
        SEL swizzledSEL = @selector(lby_setActive:withOptions:error:);
        
        Method originalMethod = class_getInstanceMethod(class, originalSEL);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSEL);
        
        BOOL didAddMethod = class_addMethod(class, originalSEL , method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
        
        if (didAddMethod) {
            class_replaceMethod(class, swizzledSEL, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}

- (BOOL)lby_setActive:(BOOL)active withOptions:(AVAudioSessionSetActiveOptions)options error:(NSError * _Nullable __autoreleasing *)outError {
    BOOL realActive = [LBYSoundManager getInstance].isPlaying ? YES : active;
    return [self lby_setActive:realActive withOptions:options error:outError];
}

@end

你可能感兴趣的:([AVAudioSession setActive:withOptions:error:]: Deactivating an audio session that has running I/O...)