While working on my previous article, an idea occurred to me. I should write an independent article covering Ionic Framework and Cordova Native Audio plugin.
 
This time I will not use ngCordova collection. For some reason, I can’t make it work with the original plugin. It’s like ngCordova Native Audio wrapper is using a different file location path, I simply can’t explain it.
 
To make this tutorial a little bit challenging, we’ll create a simple audio player.
 
 

Note: If this tutorial was helpful, need further clarification, something is not working or do you have a request for another Ionic post? Furthermore, if you don't like something about this blog, if something is bugging you, don't like how I'm doing stuff here, again leave me a comment below. I'm here to help you, I expect the same from you. Feel free to comment below, subscribe to my blog, mail me to dragan.gaic@gmail.com, or follow and mention me on twitter (@gajotres). Thanks and have a nice day!

PS. If you want my help, if possible (even if it takes you some time to do that), create a working example I can play with. Use Plunker for AngularJS based questions or jsFiddle for jQuery/jQuery Mobile based questions.


 

Table of Contents

 
 
Click here if you want to see other tutorials, or articles about the Ionic framework (themes, templates, plugins, tutorials)

Tutorials

Other Resources (themes, templates, plugins, Cordova plugins, starter apps)

Cordova Plugin Tutorials

 

Preparation

 
This tutorial requires a preconfigured environment. Skip this step if you already have this covered.
 
  • Android Environment (or iOS if you’re working on a MacOS)
  • nodeJS
  • Ionic
  • Cordova
If you don’t have previous Ionic Framework experience, find more information here: Ionic Framework | Installation Guide.
 

1. Update Ionic & Cordova

 
Before we can start, make sure you have the latest nodeJS installation, without it, you’ll not be able to install Ionic and Cordova properly.
 
If everything went well with nodeJS, let’s continue with Ionic and Cordova:
 
npm update -g cordova ionic
 

2. Create a New Project

 
ionic start IonicNativeAudioDemo blank
cd IonicNativeAudioDemo
 
Warning: Since some of you never worked with Ionic CLI. From this point and further, every time I tell you to execute something, do that inside a project folder.
 
This example requires Android platform:
 
ionic platform add android
 
For MacOS users, do it like this:
 
ionic platform add ios
 

4. Install Cordova Native Audio plugin

 
Add these:
 
cordova plugin add cordova-plugin-nativeaudio
cordova plugin add cordova-plugin-whitelist
 
If you’re using Cordova 4.0 or higher, you will need to install Whitelist plugin. Without it you’ll receive “Application Error: There was a network error.” error.
 
GitHub - Native Audio
 
 

Development

 
At this point, you should have everything set up and ready, we can start working on our example.
 
Open index.html file, add a controller to ion-pane directive:
 
  <ion-pane ng-controller="AudioController">
      <ion-header-bar class="bar-stable">
        <h1 class="title">Native Audio Example</h1>
      </ion-header-bar>
      <ion-content>
      </ion-content>
   </ion-pane>
 
Initialize AudioController controller in a app.js file:
 
app.controller('AudioController', function($scope) {

});
 
If you’re using Cordova 4+, you will need to check if there’s a Whitelist plugin installed with your project. If you have it, add this security meta tag to your index.html HEAD content:
 
<meta http-equiv="Content-Security-Policy" content="default-src *; script-src 'self' 'unsafe-inline' 'unsafe-eval' *; style-src  'self' 'unsafe-inline' *">
 
Without it your application will throw an error during the app initialization, after that it will continually throwing no security meta-tag found. While not a blocking point, constant console log warnings will make it hard to do any debugging.
 
Native Audio plugin require Cordova or Ionic ready event, so don’t forget it:
 
$ionicPlatform.ready(function() {
   // Rest of the code
});
 
To make this as easy as possible, I’ve built a JSON file holding application audio data. If you want to test this example using these files, you can find everything on the next page.
 
JSON example:
 
  var audio = [{
    id: 1,
    key: 'master',
    title: "The Master",
    track: 'audio/The_Master.mp3',
    genre: "This will be card Description"
  }, {
    id: 2,
    key: 'give',
    title: "Give",
    track: 'audio/Give.mp3',
    genre: "Alternative & Punk | Bright"
  }, {
    id: 3,
    key: 'morning',
    title: "Morning Stroll",
    track: 'audio/Morning_Stroll.mp3',
    genre: "Classical | Happy"
  }, ];
 
We’ll use this data to create our player UI:
 
 <div class="list card" ng-repeat="audio in audioTracks">

  <div class="item item-avatar">
	<img src="http://findicons.com/files/icons/2711/free_icons_for_windows8_metro/512/audio_wave.png">
	<h2>{{audio.title}}</h2>
	<p>{{audio.genre}}</p>
  </div>

  <div class="item tabs tabs-secondary tabs-icon-left">
	<a class="tab-item" href="#" ng-click="playTrack(audio.track, audio.key)">
	  <i class="icon ion-ios-play"></i>
	  Play
	</a>
	<a class="tab-item" href="#" ng-click="stopTrack(audio.key)">
	  <i class="icon ion-android-checkbox-blank"></i>
	  Stop
	</a>
  </div>

</div>
 
Every audio track will have a separate card element, and each card element will have a basic track info, play, and stop button. It will look like this:
 
 
 
Application will use these two functions for play and stop buttons:
 
$scope.playTrack = function(track, key) {
  // Preload an audio track before we play it
  window.plugins.NativeAudio.preloadComplex(key, track, 1, 1, 0, function(msg) {
	// If this is not a first playback stop and unload previous audio track
	if ($scope.player.key.length > 0) {
	  window.plugins.NativeAudio.stop($scope.player.key); // Stop audio track
	  window.plugins.NativeAudio.unload($scope.player.key); // Unload audio track
	}

	window.plugins.NativeAudio.play(key); // Play audio track
	$scope.player.key = key; // Set a current audio track so we can close it if needed 
  }, function(msg) {
	console.log('error: ' + msg); // Loading error
  });
};

$scope.stopTrack = function() {
	// If this is not a first playback stop and unload previous audio track
	if ($scope.player.key.length > 0) {
	  window.plugins.NativeAudio.stop($scope.player.key); // Stop audio track
	  window.plugins.NativeAudio.unload($scope.player.key); // Unload audio track
	  $scope.player.key = ''; // Remove a current track on unload, it will break an app if we try to unload it again in playTrack function
	}
};
 
If you for some reason need to play a much shorter nonlooping audio track (up to 10 sec) it’s better to use preloadSimple method:
 
preloadSimple: function ( id, assetPath, function(msg) {
   console.log('status: ' + msg);
}, function(msg) {
   console.log('error: ' + msg); // Loading error
});
 
Last but not least, no matter what preloading method is used don’t forget to unload it after it’s no longer needed.
 

Example

 
This is what our application looks like:
 

HTML

Application main page.
 
<!DOCTYPE html>
<html ng-app="starter">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Security-Policy" content="default-src *; script-src 'self' 'unsafe-inline' 'unsafe-eval' *; style-src  'self' 'unsafe-inline' *"> 
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    <title></title>

    <link href="lib/ionic/css/ionic.css" rel="stylesheet">

    <link href="css/style.css" rel="stylesheet">

    <!-- ionic/angularjs js -->
    <script src="lib/ionic/js/ionic.bundle.js"></script>
  
    <!-- cordova script (this will be a 404 during development) -->
    <script src="cordova.js"></script>

    <!-- your app's js -->
    <script src="js/app.js"></script>
  </head>
  <body ng-controller="AudioController">

    <ion-pane>
      <ion-header-bar class="bar-stable">
        <h1 class="title">Native Audio Example</h1>
      </ion-header-bar>
      <ion-content>
		 <div class="list card" ng-repeat="audio in audioTracks">

		  <div class="item item-avatar">
		    <img src="http://findicons.com/files/icons/2711/free_icons_for_windows8_metro/512/audio_wave.png">
		    <h2>{{audio.title}}</h2>
		    <p>{{audio.genre}}</p>
		  </div>

		  <div class="item tabs tabs-secondary tabs-icon-left">
		    <a class="tab-item" href="#" ng-click="playTrack(audio.track, audio.key)">
		      <i class="icon ion-ios-play"></i>
		      Play
		    </a>
		    <a class="tab-item" href="#" ng-click="stopTrack()">
		      <i class="icon ion-android-checkbox-blank"></i>
		      Stop
		    </a>
		  </div>

		</div>
      </ion-content>    
    </ion-pane>
  </body>
</html>
 

JavaScript

Application JavaScript file.
 
var app = angular.module('starter', ['ionic']);

app.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    if (window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if (window.StatusBar) {
      StatusBar.styleDefault();
    }
  });
});

app.controller('AudioController', function($scope, $ionicPlatform) {

  var audio = [{
    id: 1,
    key: 'master',
    title: "The Master",
    track: 'audio/The_Master.mp3',
    genre: "This will be card Description"
  }, {
    id: 2,
    key: 'give',
    title: "Give",
    track: 'audio/Give.mp3',
    genre: "Alternative & Punk | Bright"
  }, {
    id: 3,
    key: 'morning',
    title: "Morning Stroll",
    track: 'audio/Morning_Stroll.mp3',
    genre: "Classical | Happy"
  }, ];

  $scope.audioTracks = Array.prototype.slice.call(audio, 0);

  $scope.player = {
    key: '' // Holds a last active track
  }

  $ionicPlatform.ready(function() {

    $scope.playTrack = function(track, key) {
      // Preload an audio track before we play it
      window.plugins.NativeAudio.preloadComplex(key, track, 1, 1, 0, function(msg) {
        // If this is not a first playback stop and unload previous audio track
        if ($scope.player.key.length > 0) {
          window.plugins.NativeAudio.stop($scope.player.key); // Stop audio track
          window.plugins.NativeAudio.unload($scope.player.key); // Unload audio track
        }

        window.plugins.NativeAudio.play(key); // Play audio track
        $scope.player.key = key; // Set a current audio track so we can close it if needed 
      }, function(msg) {
        console.log('error: ' + msg); // Loading error
      });
    };

    $scope.stopTrack = function() {
        // If this is not a first playback stop and unload previous audio track
        if ($scope.player.key.length > 0) {
          window.plugins.NativeAudio.stop($scope.player.key); // Stop audio track
          window.plugins.NativeAudio.unload($scope.player.key); // Unload audio track
          $scope.player.key = ''; // Remove a current track on unload, it will break an app if we try to unload it again in playTrack function
        }
    };
  });
});
 
Continue to the next page