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

LockCachingAudioSource does not recover from network errors #594

Open
agersant opened this issue Nov 18, 2021 · 77 comments
Open

LockCachingAudioSource does not recover from network errors #594

agersant opened this issue Nov 18, 2021 · 77 comments
Assignees
Labels
1 backlog bug Something isn't working

Comments

@agersant
Copy link
Contributor

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:

  1. Clone the just-audio-issue-594 branch of the repository above.
  2. Run the example app under just_audio_background/example.
  3. Tap the Prefetch button. Observe the debug console messages indicating data being received.
  4. While data is being received, turn off the internet connection being used by the device (using the Android quick settings UI at the top of the screen).
  5. Observe debug messages about the download failure (and an unhandled exception call stack).
  6. Tap the Prefetch button again.
  7. Observe the debug console and notice no messages about data being transferred.

Error messages

I/flutter (14120): #0      _HttpIncoming.listen.<anonymous closure> (dart:_http/http_impl.dart:443:7)
I/flutter (14120): #1      _invokeErrorHandler (dart:async/async_error.dart:45:24)
I/flutter (14120): #2      _HandleErrorStream._handleError (dart:async/stream_pipe.dart:269:9)
I/flutter (14120): #3      _ForwardingStreamSubscription._handleError (dart:async/stream_pipe.dart:157:13)
I/flutter (14120): #4      _rootRunBinary (dart:async/zone.dart:1452:47)
I/flutter (14120): #5      _CustomZone.runBinary (dart:async/zone.dart:1342:19)
I/flutter (14120): #6      _CustomZone.runBinaryGuarded (dart:async/zone.dart:1252:7)
I/flutter (14120): #7      _BufferingStreamSubscription._sendError.sendError (dart:async/stream_impl.dart:360:15)
I/flutter (14120): #8      _BufferingStreamSubscription._sendError (dart:async/stream_impl.dart:378:7)
I/flutter (14120): #9      _BufferingStreamSubscription._addError (dart:async/stream_impl.dart:280:7)
I/flutter (14120): #10     _SyncStreamControllerDispatch._sendError (dart:async/stream_controller.dart:737:19)
I/flutter (14120): #11     _StreamController._addError (dart:async/stream_controller.dart:615:7)
I/flutter (14120): #12     _StreamController.addError (dart:async/stream_controller.dart:569:5)
I/flutter (14120): #13     _HttpParser._

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):

  • OS: Windows 10
  • Browser N/A

Smartphone (please complete the following information):

  • Device: Pixel 5 emulator
  • OS: Android API level 31

Flutter SDK version

Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 2.5.3, on Microsoft Windows [Version 10.0.19042.1348], locale en-US)
[!] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
    X cmdline-tools component is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See https://developer.android.com/studio/command-line for more details.
    X Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/windows#android-setup for more details.
[√] Chrome - develop for the web
[√] Android Studio (version 2020.3)
[√] VS Code (version 1.62.2)
[√] Connected device (3 available)

! Doctor found issues in 1 category.

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 that

await sourceResponse.stream.pipe(request.response);
was the victim.

Further debugging of the minimal repro seems to indicate that the cleanup code (

_response = null;
) never runs. Also note that this catchError handler does not return a HttpClientResponse, which is illegal.

Thanks in advance for the help!

@agersant agersant added 1 backlog bug Something isn't working labels Nov 18, 2021
@esiqveland
Copy link

esiqveland commented Jan 2, 2022

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 PlayerException: (-1004) Could not connect to the server. which I believe is because the http proxy has errored, and is not recovered.

@ryanheise
Copy link
Owner

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.

@esiqveland
Copy link

I have two:

PlayerException: (-1004) Could not connect to the server.
  File "just_audio.dart", line 778, in AudioPlayer._load
  File "<asynchronous suspension>"
  File "just_audio.dart", line 1346, in AudioPlayer._setPlatformActive.setPlatform
PlayerException: (-1004) Could not connect to the server.
  File "just_audio.dart", line 778, in AudioPlayer._load
  File "<asynchronous suspension>"
  File "just_audio.dart", line 708, in AudioPlayer.load
  File "<asynchronous suspension>"
  File "just_audio.dart", line 683, in AudioPlayer.setAudioSource
  File "<asynchronous suspension>"
  File "player_task.dart", line 146, in MyAudioHandler.skipToQueueItem
  File "<asynchronous suspension>"
  File "playerstate.dart", line 417, in PlayerCommandPlaySongInAlbum.reduce
  File "<asynchronous suspension>"
  File "store.dart", line 455, in Store._processAction_Async

Sadly I have not been able to reproduce on simulator.

@ryanheise
Copy link
Owner

Hmm, unfortunately neither of those point to the proxy.

I am guessing that an onError and/or onDone handler should probably be added on on line 1924 to handle this scenario, and then automatically set _running back to false so that it can be restarted when next needed.

@Blacksith
Copy link

Blacksith commented Jan 6, 2022

encountered same bug.

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 PlayerException: (-1004) Could not connect to the server. which I believe is because the http proxy has errored, and is not recovered.

any solution?

@ryanheise
Copy link
Owner

@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.

@Blacksith
Copy link

@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

@Blacksith
Copy link

Blacksith commented Jan 6, 2022

Hmm, unfortunately neither of those point to the proxy.

I am guessing that an onError and/or onDone handler should probably be added on on line 1924 to handle this scenario, and then automatically set _running back to false so that it can be restarted when next needed.

tried adding:
_server.doOnError((p0, p1) {
_running = false;
});
_server.doOnDone(() {
_running = false;
});
but the error is still there, maybe I got it wrong?

@ryanheise
Copy link
Owner

I was supposing to add the onError and onDone handlers to the _server.listen call.

@Blacksith
Copy link

Blacksith commented Jan 6, 2022

I was supposing to add the onError and onDone handlers to the _server.listen call.

_server.listen((request) async {
      if (request.method == 'GET') {
        final uriPath = _requestKey(request.uri);
        final handler = _handlerMap[uriPath]!;
        handler(request);
      }
      _server.doOnError((p0, p1) {
        _running = false;
      });
      _server.doOnDone(() {
        _running = false;
      });
    });

Like this? This not woking too...

@ryanheise
Copy link
Owner

I'm not at my computer right now but from memory the documentation for listen says that it takes these callbacks directly as parameters.

@Blacksith
Copy link

Blacksith commented Jan 6, 2022

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

@Blacksith
Copy link

_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);
      }
    }, onError: (){
      _running = false;
    });

if I do as described in the documentation - I keep getting PlatformException(error, No active stream to cancel, null, null)

@Blacksith
Copy link

I found a solution.
I added on line 778 _proxy.start();
After that everything started to work.
I don't claim this is the solution to the problem, but it worked for me.

@esiqveland
Copy link

It works better with this patch:

    _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;
    });

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.

@AmmarZY
Copy link

AmmarZY commented Feb 27, 2022

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.

@ryanheise
Copy link
Owner

@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 LockCachingAudioSource into your own app with a slightly different name, and then experiment with the above changes in your own version of that class.

@AmmarZY
Copy link

AmmarZY commented Mar 10, 2022

@ryanheise Thanks for the support.

The following hack worked for me

I found a solution.
I added on line 778 _proxy.start();
After that everything started to work.
I don't claim this is the solution to the problem, but it 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.

@pro100svitlo
Copy link

pro100svitlo commented Apr 2, 2022

@Blacksith @AmmarZY can you please bring some code examples of your fix?

I am asking, cos line 778 is a bit busy one...
image

Also it's not clear, should _proxy.start(); be awaited or not...

@ryanheise
Copy link
Owner

@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.

@gOzaru
Copy link

gOzaru commented Apr 4, 2022

@pro100svitlo

Also it's not clear, should _proxy.start(); be awaited or not...

No, you don't need to add it.
Just replace this code starts at line 1783 as suggested by @esiqveland :

    _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.
I used a connectivity_plus package to check the connection, and if it is disconnected; then it will display error on network. Before I found @esiqveland solution, I always ended up having an error as mentioned by @agersant. Now, I don't have that problem anymore.

SS - Error in Just Audio when it is disconnected

@gOzaru
Copy link

gOzaru commented Apr 4, 2022

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:

  • at start of buffering/downloading the song from backend
  • at the end of buffering to load the next song automatically

Then it won't get the same error again.
I tested it 5 times and it really works.

@pro100svitlo
Copy link

@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.

@ryanheise
Copy link
Owner

@pro100svitlo Your problem may be different but once the issue is fixed for LockCachingAudioSource it should also automatically be fixed for your problem, too. All that's happening in both cases is that the proxy is invoked (it happens for caching, and it happens for headers). Because there's a bug with the proxy not being able to reconnect after a network error, it affects both caching and headers similarly.

@pro100svitlo
Copy link

It is not only about reconnection.
It's also about notifying player about the error: right now error swallowed silently.

@ryanheise
Copy link
Owner

@pro100svitlo yes, but that too is something where the solution is going to be the same in both the caching and the headers cases.

@ryanheise
Copy link
Owner

On error, you would probably want to call _playbackEventSubject.addError(...).

@ryanheise
Copy link
Owner

The fixes so far have now been published on pub.dev.

@pro100svitlo
Copy link

@ryanheise
Sorry to bring this news, but my issue is still there...
I still face uncatched errors 😢

@rwrz
Copy link

rwrz commented Jul 25, 2022

I'm facing this issue as well, in production. Just audio returns the (-1004) Could not connect to the server after a while and it can't recover from it. After the first, it always returns the same. Seems the proxy is offline. The only way to recover from it is by restarting the entire App.
I will investigate it more today to find out why and where it is happening. I think it is related to switching Apps and when returning it is not working anymore.

@ryanheise
Copy link
Owner

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 _running = false which should cause the proxy to be restarted on the next request. One theory is that _running = false is never actually happening in your scenario.

@gOzaru
Copy link

gOzaru commented Sep 10, 2022

@pro100svitlo

Hey, have you tried adding this one on lines 2518 about
Proxy request failed: Exception: HTTP Status Error: 404

// 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.
And tested it again using Profile mode in Flutter project.

@rwrz
Copy link

rwrz commented Sep 12, 2022

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.

@AmmarZY
Copy link

AmmarZY commented Jul 24, 2023

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:

iOS 13 has reduced the from-the-foreground value to 30 seconds.

a. 3 minutes, when your app has moved from the foreground to the background

b. 30 seconds, when your app was resumed in the background

@rwrz
Copy link

rwrz commented Jul 24, 2023

@AmmarZY This is what I assume as well. iOS kills the network connection, leaving the proxy in an unrecoverable state.

@ryanheise
Copy link
Owner

I think there is something related to the limitations of iOS background processes

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 audio.mp3.part. When resuming, if the .part file exists, range requests should be served from it where possible, and the remainder of the audio should be downloaded and appended to that file. If the origin server doesn't support range requests, the .part file should be deleted and it should start from scratch. For now, I think it will always start from scratch if it's interrupted, which "should" also work, except for the irrecoverable state that is reported in this issue.

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.

@alexandr-efimov
Copy link

alexandr-efimov commented Aug 12, 2023

Hi, same issue for us for IOS release build. We were unable to reproduce in debug mode to get more details on it.
We are playing audio in background (with just_audio_background)

Error:
exception PlatformException: PlatformException(-1004, Could not connect to the server., null, null)

If useful, we are using stream source, with extending 'extends StreamAudioSource', to use bytes as source.
Looks like sometimes (can't say it always happens, but very often) on network issue http server can't recover and then this happens.

If any workaround present / any additional info we can be useful with, please share. Thanks

@scouech
Copy link

scouech commented Sep 14, 2023

@alexandr-efimov have you found a solution? 🤓

@ryanheise
Copy link
Owner

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.

@alexandr-efimov
Copy link

alexandr-efimov commented Sep 19, 2023

@alexandr-efimov have you found a solution? 🤓

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

@arreshashikant
Copy link

arreshashikant commented Oct 10, 2023

[ERROR] (-1004) Could not connect to the server.

#0      AudioPlayer._load (package:just_audio/just_audio.dart:851)
<asynchronous suspension>
#1      AudioPlayer._setPlatformActive.setPlatform (package:just_audio/just_audio.dart:1436)
<asynchronous suspension>
#2      AudioPlayer.play (package:just_audio/just_audio.dart:925)
<asynchronous suspension>

Steps to reproduce:

  1. Run release build on iOS (I tested on iPhone 6s, iOS 15.7.8)
  2. Play and pause any audio
  3. Put the app in background, lock the phone for some minutes
  4. Open app and try to play, you'll see the errors

just_audio: ^0.9.34

@Colton127
Copy link

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:

    _response ??=
        _fetch().catchError((dynamic error, StackTrace? stackTrace) async {
      // So that we can restart later
      _response = null;
      // Cancel any pending request
      for (final req in _requests) {
        req.fail(error, stackTrace);
      }
      return Future<HttpClientResponse>.error(error as Object, stackTrace);
    });

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:

    final httpClient = _createHttpClient(userAgent: _player?._userAgent);
    final httpRequest = await _getUrl(httpClient, uri, headers: headers);
    final response = await httpRequest.close();
    if (response.statusCode != 200) {
      httpClient.close();
      throw Exception('HTTP Status Error: ${response.statusCode}');
    }

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)

@Peetee06
Copy link

We get this issue for AudioSource.uri on Android as well as iOS devices.
On iOS we also have the error code -1004
On Android there is no code, only the error message Connection aborted

Happens as described above when the app is in the background for a while and the audio is paused/ended.

@ndmgrphc
Copy link

@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.

@Peetee06
Copy link

@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?

@swiftymf
Copy link

@ndmgrphc Do you have example of what you mean by eliminated the use of the proxy background playback? I'm curious about trying this out in my own project.

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.

@appinteractive
Copy link

appinteractive commented Apr 1, 2024

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

@startmicro
Copy link

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.

@appinteractive
Copy link

@startmicro is this also happening with my revision?

AmmarZY added a commit to AmmarZY/just_audio that referenced this issue Jun 22, 2024
@wenboLee
Copy link

my suggestion is to request preheating audioSource when Internet connected.
it work for me.

        // for a play list
        final audioSource = LockCachingAudioSource(Uri.parse(audio.url!));

        final cache = await audioSource.cacheFile;
        final exist = cache.existsSync();
        final useLocal = exist;
        if (exist) {
          audioSource.request();
        }

@GoranSustekJr
Copy link

GoranSustekJr commented Sep 21, 2024

@startmicro is this also happening with my revision?

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.

@hlarchi
Copy link

hlarchi commented Dec 29, 2024

I'm still facing the same issue on iOS release on physical device (. PlayerException: (-1004) Could not connect to the server.
@ryanheise Any updates ?

just_audio: ^0.9.42
just_audio_background: ^0.0.1-beta.14
iPhone 14 Pro Max, iOS 18.3.0

@danielgomezrico
Copy link

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),
      );

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

No branches or pull requests