I am trying to write a tweak in Theos for an iOS app, to play a silent wav in background for more background life. There might be incoming calls interrupt the sound playing, so I wrote the following notification handling. It should work, the audio player can be restarted, but playing the sound for a very short time, about 0.3s. And then the player will be deactived and stopped.
I've already tried to insert many many hook logs, still not find any clue. Anyone help me? I am very appreciated. I am new to developing iOS tweaks. Are there some tools to debug this issue?
// Register interruption handler
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(audioSessionInterruption:)
name:AVAudioSessionInterruptionNotification
object:nil];
- (void)audioSessionInterruption:(NSNotification *)notification{
NSNumber *interruptionType = [[notification userInfo] objectForKey:AVAudioSessionInterruptionTypeKey];
NSNumber *interruptionOption = [[notification userInfo] objectForKey:AVAudioSessionInterruptionOptionKey];
switch (interruptionType.unsignedIntegerValue) {
case AVAudioSessionInterruptionTypeBegan:{
NSLog(@"AVAudioSessionInterruptionTypeBegan");
} break;
case AVAudioSessionInterruptionTypeEnded:{
if (interruptionOption.unsignedIntegerValue == AVAudioSessionInterruptionOptionShouldResume) {
// Here should continue playback. Active audio session and play
// Unfortunately, the audio player playing less one second, and be deactived by something
NSLog(@"AVAudioSessionInterruptionTypeEnded");
[[AVAudioSession sharedInstance] setActive:YES error:nil];
[self.audioPlayer play];
}
} break;
default:
break;
}
}
Check the logs, I found that the AudioSession was successfully activated but was promptly deactivated.
CAReportingClient.mm:508 message {API = "[AVAudioSession etActive:activate]"; ElapsedTime = "6.517041";}: (176093659500)
CAReportingClient.mm:508 message {API = "-[AVAudioSession ategory]"; ElapsedTime = "0.158375";}: (176093659500)
CAReportingClient.mm:508 message {API = "-[AVAudioSession privateSetCategoryWithOptions:modes:routeSharingPolicy:options:]"; ElapsedTime = "5.618958";}: (176093659500)
AVAudioSession_iOS.mm:1271 Deactivating an audio session that has running I/O. All I/O should be stopped or paused prior to deactivating the audio session.
CAReportingClient.mm:508 message {API = "[AVAudioSession setActive:deactivate]"; ElapsedTime = "656.548541";}: (176093659500)
I want to find out which process deactive the audio player, and avoid it or write a hook to handle it. May be there is another notification interruption handler in this IOS app?
Finally I found the solution. Something changed audio session category options just after interruption being ended. The workaround is make a delay 3 seconds and change it back
- (void)audioSessionInterruption:(NSNotification *)notification{
NSNumber *interruptionType = [[notification userInfo] objectForKey:AVAudioSessionInterruptionTypeKey];
NSNumber *interruptionOption = [[notification userInfo] objectForKey:AVAudioSessionInterruptionOptionKey];
switch (interruptionType.unsignedIntegerValue) {
case AVAudioSessionInterruptionTypeBegan:{
// • Audio has stopped, already inactive
// • Change state of UI, etc., to reflect non-playing state
NSLog(@"AVAudioSession interruption type began");
} break;
case AVAudioSessionInterruptionTypeEnded:{
// • Make session active
// • Update user interface
// • AVAudioSessionInterruptionOptionShouldResume option
if (interruptionOption.unsignedIntegerValue == AVAudioSessionInterruptionOptionShouldResume) {
// Here you should continue playback.
NSLog(@"AVAudioSession interruption type ended");
// Something changed audio session category options, here delay 3 seconds and change it back
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
NSLog(@"Resume silence audio play from interruption");
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback
withOptions:AVAudioSessionCategoryOptionMixWithOthers error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
[self.audioPlayer play];
});
}
} break;
default:
break;
}
}