nativescriptnativescript-angularnativescript-plugin

Audio player plugin plays URL sound, but does not play local sound file


I am using NativeScript with Angular 2 and the newest Webpack workflow, and I'm using the iOS Simulator. I am using the nativescript-audio plugin to play sound files when I tap a button.

My goal is to play local sound files built into the app without using any internet connection to stream them or download them first.

I've downloaded and tried every demo app I can find and followed the instructions exactly in my own app, but I can only get the plugin to play a sound when I reference a sound file on a web server somewhere else. Attempting to play an mp3 file stored locally doesn't work.

I've also used the tns-core-modules/file-system module to search for the file I referenced, but I cannot find the file anywhere in the compiled app. It seems the file is simply not even being included in the build process, and I have no idea why.

All of the example apps I have found only play files stored on a server externally. They also are all using the outdated Legacy workflow, and none of them are using the Angular 2 system.

Here is my component.html file:

<ActionBar class="action-bar">
  <Label class="action-bar-title" text="Sound Page"></Label>
</ActionBar>

<StackLayout orientation="vertical" width="100%" height="100%">
  <Button class="btn btn-primary btn-rounded-sm" id="playButton" text="Play Sound"
    (tap)="onPlayTap($event)"></Button>
</StackLayout>

Here is my Angular 2 component.ts file:

import { Component } from "@angular/core"
import { TNSPlayer } from "nativescript-audio"

const player = new TNSPlayer()
const playerOptions =
{
  audioFile: "~/audio/session_1.mp3",
  loop: false,
  autoplay: false
}

@Component({
  selector: "SongPage",
  moduleId: module.id,
  templateUrl: "./song-page.component.html"
})
export class SongPageComponent {

  constructor()
  {
    player
      .initFromFile(playerOptions)
      .then(res => console.log(res))
      .catch(err => console.log("something went wrong...", err))
  }

  onPlayTap() { player.play() }
}

Instead of the sound file playing, I get an error from the player.initFromFile promise:

CONSOLE LOG file:///app/vendor.js:59907:39: something went wrong... Error Domain=NSOSStatusErrorDomain Code=2003334207 "(null)"

And an error from the system: CONSOLE ERROR file:///app/vendor.js:41405:24: ERROR Error: Uncaught (in promise): TypeError: null is not an object (evaluating '_this._player.play')

From what I understand, the errors are telling me it can't find the file, which appears to make sense because when I open the compiled app file, I can't find a sound file anywhere.

  1. Is there something wrong with my code itself?
  2. If not, how do I make sure the file is included in the app's compiled file and make sure the plugin can find it?

Solution

  • Make sure your audio file is bundled during build, the default build configuration do not include mp3 files but only image files, fonts, and assets.

    webpack.config.js

            // Copy assets to out dir. Add your own globs as needed.
            new CopyWebpackPlugin(
                [
                    { from: { glob: "assets/**" } },
                    { from: { glob: "fonts/**" } },
                    { from: { glob: "**/*.jpg" } },
                    { from: { glob: "**/*.png" } },
                    { from: { glob: "audio/**" } },
                ],
                { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] },
            ),
    

    Updating the CopyWebpackPlugin config with { from: { glob: "audio/**" } }, will bundle your audio folder too during the build.