native-audio icon indicating copy to clipboard operation
native-audio copied to clipboard

Cannot play files in document folder

Open gillarf opened this issue 3 years ago • 9 comments

The native audio plugin is working really well for files provided in the build, but we are downloading files from the cloud and storing them in the document folder of the app (e.g. /var/mobile/Containers/Data/Application/5CF2D476-0B24-4F2C-A331-AEECDF390071/Documents/ in my case), which is where Capacitor filesystem saves them. We would like to play them from there.

However when I try this, and I set the path to, for example "var/mobile/Containers/Data/Application/5CF2D476-0B24-4F2C-A331-AEECDF390071/Documents/1630516106806.m4a" then I get an 'Error: Asset Path is missing' error message.

Is there a way around this? I tried "/var..." and "file://var..." as the path to no avail.

Any help much appreciated.

gillarf avatar Sep 01 '21 17:09 gillarf

@gillarf I have the same issue. Did you get it working?

mariusbolik avatar Dec 15 '21 11:12 mariusbolik

@mariusbolik no unfortunately not. In the end we played them directly over http. It was the only solution. It's a shame really. Maybe someone can solve it. If it were possible to copy the file from documents to the right location, that would be OK I suppose, but i seem to remember I couldn't do this either.

gillarf avatar Dec 15 '21 13:12 gillarf

Totally my fault. It works great. I misspelled the file path! Here is my code:

  const AUDIO_FILE_DIRECTORY = 'podcast';

  async preload() {
    if (this.platform.is('capacitor')) {
      const currentEpisode = 'https://domain.com/files/my-audio-file.mp3';
      await this.downloadFile(currentEpisode);

      await NativeAudio.preload({
        assetId: 'xyz',
        assetPath: await this.getFileUri(this.extractFileNameFromUrl(currentEpisode)),
        audioChannelNum: 1,
        isUrl: true
      });
    }
  }

  private async downloadFile(url: string) {
    if (this.platform.is('capacitor')) {
      const { data } = await Http.get({
        url,
        responseType: 'blob',
        headers: {
          accept: 'audio/mp3',
          contentType: 'audio/mp3',
        }
      });
      await Filesystem.writeFile({
        directory: Directory.Data,
        path: `${AUDIO_FILE_DIRECTORY}/${this.extractFileNameFromUrl(url)}`,
        data
      });
    }
  }

  private async getFileUri(filename: string) {
    const { uri } = await Filesystem.getUri({
      directory: Directory.Data,
      path: `${AUDIO_FILE_DIRECTORY}/${filename}`
    });
    return uri;
  }

  private extractFileNameFromUrl(url: string) {
    return url.split('/').pop();
  }

mariusbolik avatar Dec 15 '21 20:12 mariusbolik

thanks @mariusbolik for your code example here (how to download a mp3 file from a server, store it locally and play it). My question is: why are you choosing this pattern instead of playing the file directly from an http stream?

More broadly speaking, why do Ionic / Capacitor app developers rely on this plugin vs a web/js audio player like, for example OpenPlayerJs ?

timstoute avatar Apr 04 '22 13:04 timstoute

Hi @timstoute, my approach is a good solution to provide an offline mode like Spotify. Meanwhile I'm using HTML5 Audio to stream audio files in Ionic / Capacitor applications. I also use HTML5 Audio to play local audio files. I'm not using the native audio plugin anymore. HTML5 is great because no plugin, framework, etc. is needed.

mariusbolik avatar Apr 04 '22 15:04 mariusbolik

@mariusbolik thanks for your reply, I appreciate the discussion. I've been using HTML5 Audio to stream audio files in my Ionic / Capacitor application and I'm running into a problem with the app on iOS 15.4 when it's the device is locked and/or the app is in background mode. When my app is in background, the code responsible to get the next track url executes, but the stream does not play. I see following error like the following:

ProcessAssertion: Failed to acquire RBS assertion 'WebKit Media Playback'

originator doesn't have entitlement com.apple.runningboard.assertions.webkit AND originator doesn't have entitlement com.apple.multitasking.systemappassertions

So, generally speaking, I'm wondering if you've had success with playback of a series of files (a playlist) while your app is in background mode?

timstoute avatar Apr 04 '22 17:04 timstoute

@timstoute sounds interesting! Does the problem only happen if the next track start automatically? Or does it also happen if a user skips a track using the lockscreen controls?

mariusbolik avatar Apr 06 '22 10:04 mariusbolik

@mariusbolik good question; the lockscreen does not show any "skip" buttons for my app, so this implies that the iOS has no knowledge of the playlist (next track), or the app's ability to play successive tracks. I'm thinking that I'll need to create a custom Capacitor plugin to work around this issue by accessing the native iOS AVQueuePlayer. I agree with you that "HTML5 is great because no plugin, framework, etc. is needed." but in this case it appears a plugin is needed. I can't find any existing Capacitor plugins that provide this audio playlist in background requirement. If you have any further thoughts or suggestions on this I'd love to hear them. I just found this and will check it out: https://github.com/phiamo/capacitor-plugin-playlist/blob/main/README.md

timstoute avatar Apr 06 '22 14:04 timstoute

@mariusbolik do you have code samples for playing a file using html5 audio from a file stored in the local filesystem? Would love to see the minimal code for that as well. Do you just set the src to a file:: url?

simon-acuitymd avatar Aug 18 '23 03:08 simon-acuitymd