-
-
Notifications
You must be signed in to change notification settings - Fork 694
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
LockCachingAudioSource
does not recover from network errors
#594
Comments
I am also seeing similar issues on ios. After being in background for a while, when coming back, it seems the proxy server has crashed or is no longer running. This results in error |
Is there more to the stack trace that traces back to just_audio plugin code? I'll be able to insert some detection and recovery code at that point. |
I have two:
Sadly I have not been able to reproduce on simulator. |
Hmm, unfortunately neither of those point to the proxy. I am guessing that an |
encountered same bug.
any solution? |
@Blacksith , the latest progress is in my previous comment. That is, I have an idea of what is going on, but haven't taken a crack at it yet. You are welcome to help experiment to make it happen sooner. |
I will also try to see what the problem could be. The only thing I know now is that this error is relevant only on ios release build, in the debug build I did not find such an error |
tried adding: |
I was supposing to add the |
Like this? This not woking too... |
I'm not at my computer right now but from memory the documentation for listen says that it takes these callbacks directly as parameters. |
can you help with that? Because I don't understand how I need to do it right |
if I do as described in the documentation - I keep getting PlatformException(error, No active stream to cancel, null, null) |
I found a solution. |
It works better with this patch:
Now it can recover to playing again half of the time, the other half the app just crashes directly, though that may be because of missing error handling on my own part. |
I have faced the same issue on iOS release on physical device. PlayerException: (-1004) Could not connect to the server. Any suggestion to resolve the issue. |
@AmmarZY we are figuring this out together, please feel welcome to join in and try out the numerous suggestions above as a starting point. You will need to make these edits to a local copy of just_audio, or alternatively you could copy the source of |
@ryanheise Thanks for the support. The following hack worked for me
The issue occurs when the iPhone screen locked normally while audio playing in the background. When the audio completed, the iOS after 30 seconds interrupts the app proxy and it stopped working as the result of the following error The PlayerException: (-1004) Could not connect to the server. |
@Blacksith @AmmarZY can you please bring some code examples of your fix? I am asking, cos line 778 is a bit busy one... Also it's not clear, should |
@esiqveland 's code looks on the right track to me. (just fyi I'll be in hospital on Monday, so probably can't give it attention until after then.) Based on my earlier experiments I wasn't certain if it caught errors in all cases, so it needs further experimentation. |
No, you don't need to add it. _server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
_server.listen((request) async {
if (request.method == 'GET') {
final uriPath = _requestKey(request.uri);
final handler = _handlerMap[uriPath]!;
handler(request);
}
},
onDone: () {
_running = false;
},
onError: (Object o, StackTrace st) {
_running = false;
}); I tested it already. |
Well, if you still have error in await sourceResponse.stream.pipe(request.response); then just replace the code starts on line 2762: // Pipe response
await sourceResponse.stream.pipe(request.response).then((value) async {
await request.response.close();
}, onError: (Object o, StackTrace st) {
dev.log("Unable to connect");
}); Whenever it gets disconnected on these conditions:
Then it won't get the same error again. |
@gOzaru okay, my case probably is different. I describe it here. It take me some time to debug example app and compare with mine. The issue comes cos I use headers with my source. Here is piece of code from library, where dramattic change happened: @override
Future<void> _setup(AudioPlayer player) async {
await super._setup(player);
if (uri.scheme == 'asset') {
_overrideUri = await _loadAsset(uri.pathSegments.join('/'));
} else if (uri.scheme != 'file' &&
!kIsWeb &&
(headers != null || player._userAgent != null)) {
await player._proxy.ensureRunning();
_overrideUri = player._proxy.addUriAudioSource(this);
}
} we are interested in this particular line: (headers != null || player._userAgent != null)) { I use headers, so in my app code goes further, and then fails inside _proxyHandlerForUri, line 3039. |
@pro100svitlo Your problem may be different but once the issue is fixed for |
It is not only about reconnection. |
@pro100svitlo yes, but that too is something where the solution is going to be the same in both the caching and the headers cases. |
On error, you would probably want to call |
The fixes so far have now been published on pub.dev. |
@ryanheise |
I'm facing this issue as well, in production. Just audio returns the |
Since each player has its own proxy, I think that creating a new player would be a way for the app to recover after this error, although that's only a workaround and it would be better to get to the bottom of why the proxy isn't being restarted. During the last round of bug fixes, we added some code to detect errors and set |
Hey, have you tried adding this one on lines 2518 about // I add this ones
int code = 0;
final HttpClientResponse response = await httpRequest.close().then((value) {
code = value.statusCode;
if (value.statusCode != 200) {
httpClient.close();
return value; //<- it used to be throw Exception(); changed it into return value;
} else {
return value;
}
}, onError: (Object o, StackTrace st) {
httpClient.close();
dev.log("[httpRequest] Error - $code");
});
// Ends here Read the comment carefully. |
I'm proposing a fix here #812. I'm using this in production for a while, it solves the issue, but I'm not very happy with the idea to catch this specific error like this. At least, it works and may help other people. |
I think there is something related to the limitations of iOS background processes, as I discussed before from my own observations to the error, it occurs almost after 30 seconds when the app is in the background and once it's resume it couldn't and it throws the platform exception. I have found the following information that confirms this assumption from this thread on stackoverflow:
|
@AmmarZY This is what I assume as well. iOS kills the network connection, leaving the proxy in an unrecoverable state. |
If it's related to background termination, just_audio_background or audio_service would allow this to work as long as the player is playing the audio at the same time as it's downloading. But then if the user pauses the audio while it's downloading, then conceivably the process could be killed and the download interrupted (which also shouldn't be a problem if only the proxy did not arrive in an irrecoverable state, and that is the main issue to fix.) As an aside, what I think is needed with that is a way to resume an interrupted download. In theory, this is possible, because the partially downloaded file should be in a file named similarly to But the real issue here is being able to cleanly handle the error case here so that the proxy does not end in an irrecoverable state. I would encourage people to try out @rwrz 's solution above. Your reports on how it works for you will help, while I also try to dig into whether this error code handles the exact set of scenarios we want to handle. |
Hi, same issue for us for IOS release build. We were unable to reproduce in debug mode to get more details on it. Error: If useful, we are using stream source, with extending 'extends StreamAudioSource', to use bytes as source. If any workaround present / any additional info we can be useful with, please share. Thanks |
@alexandr-efimov have you found a solution? 🤓 |
There is a workaround that was mentioned above in #594 (comment) . Although catching a specific error feels fragile, it is a workaround that you can try. |
no fix on our end yet, still struggling // the only solution we see is suggested by @ryanheise, will be on it in the nearest few days with try to introduce it. The main problem for us, issue happens only in Ios production build, it is really difficult to debug it |
[ERROR] (-1004) Could not connect to the server.
Steps to reproduce:
|
Uncaught errors involving LockCachingAudioSource and lack of network connectivity filled my sentry logs. Based upon my testing, the error is thrown within the _fetch function when _getUrl is called. The error not being caught is actually a quirk in Dart's error handling. _fetch is called on just_audio starting on line 3013:
We would expect .catchError to catch any errors thrown by _fetch, but it doesn't because of how Dart handles exceptions. Instead, the exception thrown by _fetch is unhandled. Within _fetch, the code throwing an error when there is no internet connection is:
The getUrl method in specific throws an exception when the connection fails. I was at my wits end with this issue, and came up with a rather "dirty" fix. You can see what I did here: https://github.com/Colton127/just_audio/blob/feature/treadmill/just_audio/lib/just_audio.dart (note that I am using the "treadmill" branch, which fixes an issue on iOS when a large amount of items are in a playlist.) I moved the code throwing the error (httprequest/response) to a new method "_createResponse", which correctly handles the exception. I passed the response from the httpClient to the _fetch function directly, thus the _fetch function no longer establishes the connection. This appears to fix both unhandled exceptions being thrown, and OPs issue where a download cannot be restarted when the connection is interrupted. Interestingly, the download actually resumed where it left off upon reestablishing a connection on my iPhone X, but not my S22 ultra. I feel like my fix still needs work (and testing) before release. On a side note, I have opened a pull request to fix a smaller issue involving PathNotFoundException when a LockCachingAudioSource is closed shortly after a request is made (#1076) |
We get this issue for Happens as described above when the app is in the background for a while and the audio is paused/ended. |
@Peetee06 I traced this issue back to the proxy -- once I eliminated the use of the proxy background playback worked fine. The proxy is broken from what I've seen. It goes to sleep and can't be woken up without exposing private methods and including that logic from your code. |
@ndmgrphc thank you for the tip! I don't fully understand what the proxy is for and if eliminating its use has any side effects I may want to be aware of, though. Do you know what I need to be aware of in the case of removing its use? |
@ndmgrphc Do you have example of what you mean by Currently I'm re-initializing the audio player any time we resume play after being paused so I can avoid the error that this thread is about. It works, but is not ideal and I'd like to find something better. |
So I did an updated pull-request from @rwrz work, and it works so far for me. #1218 Anyone can check it out by using the following dependency: # just_audio: ^0.9.37
just_audio:
git:
url: https://github.com/appinteractive/just_audio.git
ref: 555e945d219be8c91dcdda198c0a2a495f6e9f1a
path: just_audio |
The error is still present in the current version 0.9.37. The use case is quite simple. I'm using stream audio sources. In release mode, simply background the app for a few seconds, and after a while, the error message -1004 Could not connect to server appears. iOS as the environment. The only workaround that works for me is to initialize the audioPlayer every time. However, this cannot be the solution. |
@startmicro is this also happening with my revision? |
my suggestion is to request preheating audioSource when Internet connected.
|
Yes, I have the same issue; -1004 when I lock the phone, track that is playing finishes and 30 seconds pass. Also using audio service, LockCachinAudioSource. I tried your fix but it does not work, I still get the same error. |
I'm still facing the same issue on iOS release on physical device (. PlayerException: (-1004) Could not connect to the server. just_audio: ^0.9.42 |
I get the issue @hlarchi after some time playing, not at the start 🤔 I initialize it like this: final audioSources = tracks.map((track) {
final artists = track.artistNames.join(', ');
final artist = artists.isNotEmpty ? artists : 'Unknown artist';
final album = track.album ?? 'Unknown album';
final imageUrl = track.imageUrl ?? Config.defaultImageUrl;
final audioUri = Uri.parse(track.audioUrl);
return LockCachingAudioSource(
audioUri,
tag: MediaMetadata(
title: track.title,
artist: artist,
album: album,
artworkUri: Uri.parse(imageUrl),
audioUri: audioUri,
),
);
}).toList();
await _player.setAudioSource(
preload: true,
initialIndex: index,
initialPosition: Duration.zero,
ConcatenatingAudioSource(children: audioSources),
); |
Which API doesn't behave as documented, and how does it misbehave?
When calling
LockCachingAudioSource.request()
after a network error occurs, no bytes will be transferred.Minimal reproduction project
https://github.com/agersant/just_audio/tree/just-audio-issue-594
To Reproduce (i.e. user steps, not code)
Steps to reproduce the behavior:
just-audio-issue-594
branch of the repository above.just_audio_background/example
.Prefetch
button. Observe the debug console messages indicating data being received.Prefetch
button again.Error messages
Expected behavior
No exception callstack should appear in the log, and the download should restart or resume when tapping
Prefetch
.Screenshots
2021-11-18.03-05-26.mp4
Desktop (please complete the following information):
Smartphone (please complete the following information):
Flutter SDK version
Additional context
For some reason, the debugger doesn't seem to catch the exception in
just_audio
code with this minimal repro. In my full app, I was able to determine thatjust_audio/just_audio/lib/just_audio.dart
Line 3009 in 1c6598c
Further debugging of the minimal repro seems to indicate that the cleanup code (
just_audio/just_audio/lib/just_audio.dart
Line 2899 in 1c6598c
catchError
handler does not return aHttpClientResponse
, which is illegal.Thanks in advance for the help!
The text was updated successfully, but these errors were encountered: