Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Player becomes unresponsive after failure to play track. #56

Closed
curiousdustin opened this issue Apr 24, 2019 · 9 comments · Fixed by #60
Closed

Player becomes unresponsive after failure to play track. #56

curiousdustin opened this issue Apr 24, 2019 · 9 comments · Fixed by #60
Labels
bug Something isn't working

Comments

@curiousdustin
Copy link

Describe the bug
After there is a problem playing a track, and the AVPlayer status changes to failed, the player becomes unresponsive and will not play any other track. Every command after reaching this state results in an error.

To Reproduce
I found this error when I was attempting to play a track. I later discovered that there was image metadata in the track. After removing the image metadata, the track does not result in an error.

I cannot post the test file publicly, but I can provide it privately if it helps to debug.

While modifying this audio file fixes the immediate issue, there is still the underlying issue of the player becoming unresponsive after a failure.

Expected behavior
The player should be able to recover after failing to play a track and resume normal operation when attempting to play a different track.

Info:

  • iPhoneX iOS 12.1
  • SwiftAudio Version 0.7.2

Additional context
I am using SwiftAudio as part of react-native-track-player, which is maintained by @dcvz.

However, I have recreated this issue within the SwiftAudio example by replacing one of the example tracks with the track I have been having issues with. The default example track play fine until I try to play the problem track. After that, the example tracks will no longer play.

Suggested Solution
Apple docs say that when AVPlayer status changes to 'failed', the AVPlayer instance can no longer be used and must be replaced with a new instance.
https://developer.apple.com/documentation/avfoundation/avplayer/1388096-status

I tried this, and it seems to resolve the issue. Check out this commit on my fork.

However, I did not create a PR because I am not proficient in swift, and I don't feel I have a good enough grasp on the overall structure of this library in order to implement this fix in the best way possible.

For instance, I don't know if it would be better to do this in response to the failure, or to check before the next action and recreate the instance on demand. Also, I'm not sure if the wrapper should be re-created or just the AVPlayer.

@curiousdustin
Copy link
Author

Also I just realized my quick attempt at a fix seems to break the lock screen controls. So yeah, looking for someone with more knowledge on this to implement a better fix.

@curiousdustin
Copy link
Author

The busted lock screen issue appears to be related to the AVAudioSession category getting messed up. I'm not sure if it is something I'm doing wrong, or if the session also needs to be reset somehow when a failure like this occurs.

If I add logging of the category in AVPlayerWrapper like this:

func player(statusDidChange status: AVPlayer.Status) {
	switch status {

	case .readyToPlay:
		print(".readyToPlay category:")
		print(AVAudioSession.sharedInstance().category)
		...
		break

	case .failed:
		print(".failed category:")
		print(AVAudioSession.sharedInstance().category)
		...
		break
	}
}

I get the following output on successful tracks:

.readyToPlay category:
AVAudioSessionCategory(_rawValue: AVAudioSessionCategoryPlayback)

I get this on the failed track:

.readyToPlay category:
2019-04-24 16:38:15.555249-0600 pinna[1152:732947] [avas] AVAudioSessionUtilities.h:112:GetProperty: AudioSessionGetProperty ('acat') failed with error: '!ini'
2019-04-24 16:38:15.555266-0600 pinna[1152:732947] [avas] AVAudioSessionUtilities.h:127:GetProperty_DefaultToZero: AudioSessionGetProperty ('acat') failed with error: '!ini'
2019-04-24 16:38:15.555273-0600 pinna[1152:732947] [avas] AVAudioSession.mm:830:-[AVAudioSession category]: No valid string for category: 0
AVAudioSessionCategory(_rawValue: )
.failed category:
2019-04-24 16:38:15.559898-0600 pinna[1152:732947] [avas] AVAudioSessionUtilities.h:112:GetProperty: AudioSessionGetProperty ('acat') failed with error: '!ini'
2019-04-24 16:38:15.559933-0600 pinna[1152:732947] [avas] AVAudioSessionUtilities.h:127:GetProperty_DefaultToZero: AudioSessionGetProperty ('acat') failed with error: '!ini'
2019-04-24 16:38:15.559951-0600 pinna[1152:732947] [avas] AVAudioSession.mm:830:-[AVAudioSession category]: No valid string for category: 0
AVAudioSessionCategory(_rawValue: )

To confirm, when it fails, it does report the change to both .readyToPlay and then .failed.

@curiousdustin
Copy link
Author

curiousdustin commented Apr 24, 2019

The symptoms after this are that locking the device, or backgrounding the app, pause playback. When resuming the app, playback continues. Also the lock screen controls are unresponsive.

So it seems like it is defaulting to a different category.

@jorgenhenrichsen jorgenhenrichsen added the bug Something isn't working label Apr 25, 2019
@jorgenhenrichsen
Copy link
Owner

Thanks for the detailed report!
Will look into this when I have time ✅

@curiousdustin
Copy link
Author

@jorgenhenrichsen, I have taken another stab at this. I think I have resolved the issues with the AVAudioSession.

After the failure happens, the session category needs to be set again for some reason. Otherwise it behaves like it is set to default (i think).

Here is my updated attempt: curiousdustin@6a06eba

This time, I have included modifications to your example app, so you can test it out if you like.

Again, I have not created a PR because I have a hunch there will be a better way to go about this.

@jorgenhenrichsen
Copy link
Owner

I tested with your failing track, but it does not fail for me? What it does however is freezing the UI for 10-15 seconds before eventually playing normally, which i suspect comes from the fact that the asset is not loaded async. I will try to play the track on #51 to see if it freezes there as well.
I tried your branch and the track did not fail for me there either, but froze the UI completely for a while before starting playback.

You are correct, the AVPlayer should be switched out after it has failed. I am considering on wether switching out the AVPlayer, or just the whole AVPlayerWrapper is the best approach. I am a bit busy these days, but will eventually come around to these issues.

@curiousdustin
Copy link
Author

Are you testing on device? The track eventually plays for me on simulator but fails on device.

Also I did notice that the async related changes in #51 , do make it so that the track does not completely fail. However, as you said, either way, the player DOES need to gracefully recover from a failure IF it does happen somehow.

This ticket is more about recovering from a failure than avoiding this specific failure from this specific track.

@jorgenhenrichsen
Copy link
Owner

Ah, I tested on simulator.
Yeah, I get that it was not about the specific track, but about recovering from failure in general 👍

@curiousdustin
Copy link
Author

Thanks for implementing a fix! I’ll try to test it out sometime this week. 😁

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants