Sound Effects in Ionic

Sound Effects using HTML5 and Native Audio in Ionic



·

A big part of making a mobile application feel high quality is to provide immediate and obvious feedback for a user’s actions. When a user performs some action, you will want to communicate with them in some way that whatever action they have performed has been successful. That information can be communicated visually, through sound, or even through a physical sensation like vibration.

If you’ve used the Facebook application, you will likely have noticed that as you use the application various sound effects play. As you switch between tabs, for example, a little popping sound plays. Although I obviously can’t speak to Facebook’s particular motivations for including this, it does help add to the feeling of responsiveness as you use the application – even though it’s probably annoying everyone else in the room.

In this tutorial, we are going to walk through how to add a similar sound effect when switching between tabs in an Ionic application. We are going to design this in such a way that it will use standard HTML5 audio by default, but it will use native audio when built with Cordova.

When using the HTML5 audio, the audio is loaded on the fly, so there is a slight, but noticeable, delay before the audio plays. When using native audio, the sound is preloaded and can be played back instantly.

Before We Get Started

Last updated for Ionic 3.0.1

Before you go through this tutorial, you should have at least a basic understanding of Ionic concepts. You must also already have Ionic set up on your machine.

If you’re not familiar with Ionic already, I’d recommend reading my Ionic Beginners Guide or watching my beginners series first to get up and running and understand the basic concepts. If you want a much more detailed guide for learning Ionic, then take a look at Building Mobile Apps with Ionic.

1. Generate a New Ionic Application

We are going to generate a new project based on the tabs template – since we are going to implement the sound effect when switching between tabs this will save us a lot of work.

Run the following command to generate a new Ionic application:

ionic start ionic-tab-sounds tabs

Once that has finished generating, make it your working directory:

cd ionic-tab-sounds

As I mentioned in the introduction, we will be using both HTML5 and native sound. To use the native sound we will need to use the native API, which we can access through the NativeAudio Cordova plugin. This is available through Ionic Native, so we will be using that.

Run the following commands to set up the NativeAudio plugin:

ionic plugin add cordova-plugin-nativeaudio
npm install @ionic-native/native-audio --save

We will also be creating a provider that will handle switching between the HTML5 and native audio without us having to worry about what platform we are running on. This will make it much easier to test through the browser, and if you want to deploy your application to the browser this will of course also be useful.

Run the following command to generate a SmartAudio provider

ionic g provider SmartAudio

Now we are just going to modify the app.module.ts file to set up our SmartAudio provider and add the provider for the NativeAudio plugin.

Modify src/app/app.module.ts to reflect the following:

import { NgModule, ErrorHandler } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';

import { AboutPage } from '../pages/about/about';
import { ContactPage } from '../pages/contact/contact';
import { HomePage } from '../pages/home/home';
import { TabsPage } from '../pages/tabs/tabs';

import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';

import { SmartAudio } from '../providers/smart-audio';
import { NativeAudio } from '@ionic-native/native-audio';

@NgModule({
  declarations: [
    MyApp,
    AboutPage,
    ContactPage,
    HomePage,
    TabsPage
  ],
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    AboutPage,
    ContactPage,
    HomePage,
    TabsPage
  ],
  providers: [
    StatusBar,
    SplashScreen,
    SmartAudio,
    NativeAudio,
    {provide: ErrorHandler, useClass: IonicErrorHandler}
  ]
})
export class AppModule {}

2. Implement the Smart Audio Provider

Now we are going to implement the SmartAudio provider, which is reasonably simple, but we are going to talk through it bit by bit.

Modify src/providers/smart-audio.ts to reflect the following:

import { Injectable } from '@angular/core';
import { Platform } from 'ionic-angular';
import { NativeAudio } from '@ionic-native/native-audio';

@Injectable()
export class SmartAudio {

    audioType: string = 'html5';
    sounds: any = [];

    constructor(public nativeAudio: NativeAudio, platform: Platform) {

        if(platform.is('cordova')){
            this.audioType = 'native';
        }

    }

    preload(key, asset) {

        if(this.audioType === 'html5'){

            let audio = {
                key: key,
                asset: asset,
                type: 'html5'
            };

            this.sounds.push(audio);

        } else {

            this.nativeAudio.preloadSimple(key, asset);

            let audio = {
                key: key,
                asset: key,
                type: 'native'
            };

            this.sounds.push(audio);
        }       

    }

    play(key){

        let audio = this.sounds.find((sound) => {
            return sound.key === key;
        });

        if(audio.type === 'html5'){

            let audioAsset = new Audio(audio.asset);
            audioAsset.play();

        } else {

            this.nativeAudio.play(audio.asset).then((res) => {
                console.log(res);
            }, (err) => {
                console.log(err);
            });

        }

    }

}

At the top we set up some member variables, these will keep track of whether we are using HTML5 or native audio, and the sounds array will keep track of any sounds that we want to use throughout the application.

In the constructor function we simply detect whether or not we are running on Cordova, and if we are we switch the audioType to native. This will determine which method is used to play the audio.

We have a preload function, which we will call at app startup to load in the audio that we want to use. The key will be the string we use to reference a specific sound, and the asset will be the path to where that audio file is located. In the case of HTML5 audio, we just create an object that contains the key and asset. If we are using native audio, then we first preload the audio using preloadSimple and then we just store the key for both the key and asset values in the object (we won’t need the file path to play the sound later). Once the appropriate audio object has been created, we push it into our sounds array.

In the play function, we supply it with the key that we used to preload the audio asset. This will find that asset in the sounds array and then use the appropriate method to play it (depending on whether we are using the HTML5 audio or the native audio).

That’s all there is to this provider – we preload some audio, and then reference it by a key later to play it.

3. Trigger Sound on Tab Switches

Now that we have our provider implemented, we are going to use it to play a sound every time the user switches between tabs. You could use this provider for just about any purpose though – one thing to keep in mind is that if you want to play longer sounds (like music) you should use the preloadComplex method instead of preloadSimple. Take a look at the documentation for more information.

Modify src/app/app.component.ts to reflect the following:

import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import { TabsPage } from '../pages/tabs/tabs';

import { SmartAudio } from '../providers/smart-audio';

@Component({
  templateUrl: 'app.html'
})
export class MyApp {
  rootPage:any = TabsPage;

  constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen, smartAudio: SmartAudio) {
    platform.ready().then(() => {
      statusBar.styleDefault();
      splashScreen.hide();

      smartAudio.preload('tabSwitch', 'assets/audio/clickSound.mp3');

    });
  }
}

In order to use the audio with our service later, we need to first preload it, which we do with the following line:

smartAudio.preload('tabSwitch', 'assets/audio/clickSound.mp3');

Now we will be able to play this sound later by using the tabSwitch key. I’ve just used a free sound I got from freesound.org for this example.

In order to trigger this sound on every tab switch, we are going to add an event binding to the tabs in the template.

Modify src/pages/tabs/tabs.html to reflect the following:

<ion-tabs>
  <ion-tab (ionSelect)="changeTab()" [root]="tab1Root" tabTitle="Home" tabIcon="home"></ion-tab>
  <ion-tab (ionSelect)="changeTab()" [root]="tab2Root" tabTitle="About" tabIcon="information-circle"></ion-tab>
  <ion-tab (ionSelect)="changeTab()" [root]="tab3Root" tabTitle="Contact" tabIcon="contacts"></ion-tab>
</ion-tabs>

Any time the user switches to a tab with the (ionSelect) event binding attached, it will trigger the changeTab function. Now we just need to define that function.

Modify src/pages/tabs/tabs.ts to reflect the following:

import { Component } from '@angular/core';
import { AboutPage } from '../about/about';
import { ContactPage } from '../contact/contact';
import { HomePage } from '../home/home';
import { SmartAudio } from '../../providers/smart-audio';

@Component({
  templateUrl: 'tabs.html'
})
export class TabsPage {

    tab1Root = HomePage;
    tab2Root = AboutPage;
    tab3Root = ContactPage;

    constructor(public smartAudio: SmartAudio) {

    }

    changeTab() {
        this.smartAudio.play('tabSwitch');
    }

}

All we need to do is call the play function on our SmartAudio provider and provide it with the appropriate key. The sound should now play whenever the user switches between tabs.

Summary

One of the biggest benefits of Ionic is that it allows us to easily run an application across multiple platforms, both web and native. When we run into situations like this where perhaps there is a preferable solution available that relies on a native API through a plugin, I think it is a good idea to create some service like this that abstracts away the implementation details and allows you to use it consistently no matter what platform you are running on.

What to watch next...