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

Play a remote file and cache the file at the same time #374

Open
somaria opened this issue Dec 30, 2019 · 16 comments
Open

Play a remote file and cache the file at the same time #374

somaria opened this issue Dec 30, 2019 · 16 comments
Labels

Comments

@somaria
Copy link

somaria commented Dec 30, 2019

Any suggestion on how I could play a remote files and store the files in cache for faster playing next time?

Anyone has tried using audioplayers with Flutter Cache Manager to cache the audio files? Is that even possible?

@georgezhang
Copy link

+1

@luanpotter
Copy link
Member

I believe we could make AudioCache support this kind of caching. Would love to see a PR for that!

@shantiwebsolution
Copy link

+1

1 similar comment
@freddydrodev
Copy link

+1

@freddydrodev
Copy link

hi @somaria this is the technic I am actually using. I am also looking for improvement for this technic or its implementation in the play method. because it will download the file two time in my opinion. one from the remote action and one from the cache. but the next time it is ok I think  :).
Note: I am using provider to make actions global

//invoked only when the user want to play a new song
//may be when he clicks on a new music to cache item only once
  play({bool isNew = false, bool isLocal = false}) async {
    // _cache.emptyCache(); //used for testing
    //set the loading to true
    //setLoading(true); in case you want to show a loading
    _player.stop();
    //checking if the file is stored in the cache
    FileInfo info;

    // this is an object from my provider class
   // that let me store info about the current music
    final _url = _data['url'];

    //set the url to be the cached one if exists
    String path = _url;

    //ios does not support cache because files are store as mpeg which it does not read
    if (!Platform.isIOS) {
      
      info = await _cache.getFileFromCache(_url);
      // if the file is not in the cache we cache it for the next time

      path = info != null ? info.file.path : path;
    }

    final int result = await _player.play(
      path,
      isLocal: info != null,
      stayAwake: true,
    );

    notifyListeners();

    //cache the song after playing it
    // skiping ios as it does not support mpeg. 
    //another option could be to store the file locally in a
    // custom folder as IOS does not show up folders
    if (!Platform.isIOS && result == 1) {
      if (info == null) {
        await _cache.getSingleFile(_url);
      }
    }
  }

@somaria
Copy link
Author

somaria commented Feb 6, 2020

@feroult

// skiping ios as it does not support mpeg. 

so this works only for Android and not in iOS?

@volgin
Copy link
Contributor

volgin commented Feb 7, 2020

You can download a file, and then play it - on all platforms. It's impossible to "play and cache" and the same time.

Audio players start playing files before they download the complete file - as soon as they have enough "chunks" for a smooth playback. Each player has its own logic for deciding when it's safe to start playing.

I don't know if you can pass individual chunks to Android and iOs players. If it's possible, then you can manage chunking in your own code - get a chunk, give it to a player, and write it out to the file. But this will not be a simple implementation, even if it's possible.

Another option would be for a player to manage all the chunking, and then give you the file after it finished loading it. Again, I don't know for sure if any player can do it, but I don't think so.

@somaria
Copy link
Author

somaria commented Feb 8, 2020

This can be done using Flutter Cache Manager for Android. The test code is here https://github.com/somaria/flutter_cache_try
It doesn't work for iOS and I am still trying to figure out why.
If anyone have a solution for iOS, please let me know.

@volgin
Copy link
Contributor

volgin commented Feb 8, 2020

@somaria In your code the playback starts only after the entire file is downloaded to a device. It will lead to a noticeable delay unless your files are very small.

BTW, it’s not a good practice to call async methods from setState().

@somaria
Copy link
Author

somaria commented Feb 9, 2020

@volgin , yes the mp3 files are very small, but they are many of them. Now there are already a few hundreds.

Did you notice that the code doesn't work in iOS? It could be that AudioPlayers doesn't support playing files from iOS device. It only supports playing files from asset folder in iOS. I need to get a confirmation on this.

@volgin
Copy link
Contributor

volgin commented Feb 9, 2020

I play files from iOs devices using AudioPlayers every day. mp3, m4a - they all work perfectly.

Check the file path that you get from the cache manager.

@freddydrodev
Copy link

This can be done using Flutter Cache Manager for Android. The test code is here https://github.com/somaria/flutter_cache_try
It doesn't work for iOS and I am still trying to figure out why.
If anyone have a solution for iOS, please let me know.

it does not work on ios because the files are saved in mpeg. which ios does not support

@freddydrodev
Copy link

@feroult

// skiping ios as it does not support mpeg. 

so this works only for Android and not in iOS?

yes you can still play form ios but the file is not cached

@somaria
Copy link
Author

somaria commented Feb 10, 2020

@feroult
Oh, I didn't know that. So now we have no solution at all?

I really prefer using Flutter Cache Manager, it works perfectly in Android.

@freddydrodev
Copy link

@feroult
Oh, I didn't know that. So now we have no solution at all?

I really prefer using Flutter Cache Manager, it works perfectly in Android.

the last thing we may try is to download the file itself using and store in a custom folder for ios. I think IOS does not show local file such as musics. and then from sqflite save the path and access it. I hope you see the idea

@x94c2017
Copy link

see Baseflow/flutter_cache_manager#140

  Future<void> _playBgm() async {
    await _bgm.play(await _fixMp3Url());
  }

  /// when Flutter Cache Manager delete it
  Future<String> _fixMp3Url() async {
    var s1 = 'https//a.b/c.mp3';
    var f = await DefaultCacheManager().getSingleFile(s1);

    if (!Platform.isAndroid && s1.endsWith('.mp3')) {
      var s2 = s1 + '.mp3';
      var resp;
      var cacheFile = await DefaultCacheManager().getFileFromCache(s2);
      if (cacheFile == null) {
        var f2 = await DefaultCacheManager()
            .putFile(s2, await f.readAsBytes(), fileExtension: 'mp3');
        resp = f2.path;
      } else {
        resp = cacheFile.file.path;
      }
      return resp;
    }
    return f.path;
  }

it works well now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

9 participants