Android Play Audio File In Background Service Example

This article will show you how to communicate between activity and background service in android. It will play, pause and stop a web audio file in android background service in this example. It will also update activity progress bar from background service to display audio playing process.

use serviceconnection to call background service methods in activity

1. Activity Communicate With Background Service Required Components.

From above picture, we can see to call and control background service in activity, you need below four component.

  1. Activity ( PlayBackgroundAudioActivity ) : In this activity we use below code to bind android background service ( AudioService ) with this activity.
    Intent intent = new Intent(PlayBackgroundAudioActivity.this, AudioService.class);
    
    // Below code will invoke serviceConnection's onServiceConnected method.
    bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
  2. ServiceConnection : This is an instance of android.content.ServiceConnection class, it’s onServiceConnected method is invoked when activity bind audio service. In that method, it will cast and assign iBinder input parameter to activity’s object variable.
  3. Background Service ( AudioService ) : It only contain an instance of  AudioServiceBinder ( the fourth component ), and return this binder instance in it’s onBind method.
  4. Custom Binder Class ( AudioServiceBinder ) : This class is a subclass of android.os.Binder. It will implement all audio player start, pause and stop methods.

2. Play Web Audio Fie In Background Service Example.

android play web audio file in background service object

Below is this example files structure.

play audio in android background service project file structure

2.1 Main Activity Java File.

PlayBackgroundAudioActivity.java

ServiceConnection is a private instance variable of this class.

package com.dev2qa.example.audio.background;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.dev2qa.example.R;

public class PlayBackgroundAudioActivity extends AppCompatActivity {

    private AudioServiceBinder audioServiceBinder = null;

    private Handler audioProgressUpdateHandler = null;

    // Show played audio progress.
    private ProgressBar backgroundAudioProgress;

    private TextView audioFileUrlTextView;

    // This service connection object is the bridge between activity and background service.
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            // Cast and assign background service's onBind method returned iBander object.
            audioServiceBinder = (AudioServiceBinder) iBinder;
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_play_background_audio);

        setTitle("dev2qa.com - Play Audio Use Background Service");

        // Bind background audio service when activity is created.
        bindAudioService();

        final String audioFileUrl = "http://www.dev2qa.com/demo/media/test.mp3";

        backgroundAudioProgress = (ProgressBar)findViewById(R.id.play_audio_in_background_service_progressbar);

        // Get audio file url textview.
        audioFileUrlTextView = (TextView)findViewById(R.id.audio_file_url_text_view);
        if(audioFileUrlTextView != null)
        {
            // Show web audio file url in the text view.
            audioFileUrlTextView.setText("Audio File Url. \r\n" + audioFileUrl);
        }

        // Click this button to start play audio in a background service.
        Button startBackgroundAudio = (Button)findViewById(R.id.start_audio_in_background);
        startBackgroundAudio.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // Set web audio file url
                audioServiceBinder.setAudioFileUrl(audioFileUrl);

                // Web audio is a stream audio.
                audioServiceBinder.setStreamAudio(true);

                // Set application context.
                audioServiceBinder.setContext(getApplicationContext());

                // Initialize audio progress bar updater Handler object.
                createAudioProgressbarUpdater();
                audioServiceBinder.setAudioProgressUpdateHandler(audioProgressUpdateHandler);

                // Start audio in background service.
                audioServiceBinder.startAudio();

                backgroundAudioProgress.setVisibility(ProgressBar.VISIBLE);

                Toast.makeText(getApplicationContext(), "Start play web audio file.", Toast.LENGTH_LONG).show();
            }
        });

        // Click this button to pause the audio played in background service.
        Button pauseBackgroundAudio = (Button)findViewById(R.id.pause_audio_in_background);
        pauseBackgroundAudio.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                audioServiceBinder.pauseAudio();
                Toast.makeText(getApplicationContext(), "Play web audio file is paused.", Toast.LENGTH_LONG).show();
            }
        });

        // Click this button to stop the media player in background service.
        Button stopBackgroundAudio = (Button)findViewById(R.id.stop_audio_in_background);
        stopBackgroundAudio.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                audioServiceBinder.stopAudio();
                backgroundAudioProgress.setVisibility(ProgressBar.INVISIBLE);
                Toast.makeText(getApplicationContext(), "Stop play web audio file.", Toast.LENGTH_LONG).show();
            }
        });
    }

    // Bind background service with caller activity. Then this activity can use
    // background service's AudioServiceBinder instance to invoke related methods.
    private void bindAudioService()
    {
        if(audioServiceBinder == null) {
            Intent intent = new Intent(PlayBackgroundAudioActivity.this, AudioService.class);

            // Below code will invoke serviceConnection's onServiceConnected method.
            bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
        }
    }

    // Unbound background audio service with caller activity.
    private void unBoundAudioService()
    {
        if(audioServiceBinder != null) {
           unbindService(serviceConnection);
        }
    }

    @Override
    protected void onDestroy() {
        // Unbound background audio service when activity is destroyed.
        unBoundAudioService();
        super.onDestroy();
    }

    // Create audio player progressbar updater.
    // This updater is used to update progressbar to reflect audio play process.
    private void createAudioProgressbarUpdater()
    {
        /* Initialize audio progress handler. */
        if(audioProgressUpdateHandler==null) {
            audioProgressUpdateHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    // The update process message is sent from AudioServiceBinder class's thread object.
                    if (msg.what == audioServiceBinder.UPDATE_AUDIO_PROGRESS_BAR) {

                        if( audioServiceBinder != null) {
                            // Calculate the percentage.
                            int currProgress =audioServiceBinder.getAudioProgress();

                            // Update progressbar. Make the value 10 times to show more clear UI change.
                            backgroundAudioProgress.setProgress(currProgress*10);
                        }
                    }
                }
            };
        }
    }
}

2.2 Background Service Class.

AudioService.java

package com.dev2qa.example.audio.background;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class AudioService extends Service {

    private AudioServiceBinder audioServiceBinder = new AudioServiceBinder();

    public AudioService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return audioServiceBinder;
    }
}

2.3 Binder Class.

AudioServiceBinder.java

package com.dev2qa.example.audio.background;

import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Binder;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;

import java.io.IOException;

/**
 * Created by Jerry on 2/15/2018.
 */

public class AudioServiceBinder extends Binder {

    // Save local audio file uri ( local storage file. ).
    private Uri audioFileUri = null;

    // Save web audio file url.
    private String audioFileUrl = "";

    // Check if stream audio.
    private boolean streamAudio = false;

    // Media player that play audio.
    private MediaPlayer audioPlayer = null;

    // Caller activity context, used when play local audio file.
    private Context context = null;

    // This Handler object is a reference to the caller activity's Handler.
    // In the caller activity's handler, it will update the audio play progress.
    private Handler audioProgressUpdateHandler;

    // This is the message signal that inform audio progress updater to update audio progress.
    public final int UPDATE_AUDIO_PROGRESS_BAR = 1;

    public Context getContext() {
        return context;
    }

    public void setContext(Context context) {
        this.context = context;
    }

    public String getAudioFileUrl() {
        return audioFileUrl;
    }

    public void setAudioFileUrl(String audioFileUrl) {
        this.audioFileUrl = audioFileUrl;
    }

    public boolean isStreamAudio() {
        return streamAudio;
    }

    public void setStreamAudio(boolean streamAudio) {
        this.streamAudio = streamAudio;
    }

    public Uri getAudioFileUri() {
        return audioFileUri;
    }

    public void setAudioFileUri(Uri audioFileUri) {
        this.audioFileUri = audioFileUri;
    }

    public Handler getAudioProgressUpdateHandler() {
        return audioProgressUpdateHandler;
    }

    public void setAudioProgressUpdateHandler(Handler audioProgressUpdateHandler) {
        this.audioProgressUpdateHandler = audioProgressUpdateHandler;
    }

    // Start play audio.
    public void startAudio()
    {
        initAudioPlayer();
        if(audioPlayer!=null) {
            audioPlayer.start();
        }
    }

    // Pause playing audio.
    public void pauseAudio()
    {
        if(audioPlayer!=null) {
            audioPlayer.pause();
        }
    }

    // Stop play audio.
    public void stopAudio()
    {
        if(audioPlayer!=null) {
            audioPlayer.stop();
            destroyAudioPlayer();
        }
    }

    // Initialise audio player.
    private void initAudioPlayer()
    {
        try {
            if (audioPlayer == null) {
                audioPlayer = new MediaPlayer();

                if (!TextUtils.isEmpty(getAudioFileUrl())) {
                    if (isStreamAudio()) {
                        audioPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
                    }
                    audioPlayer.setDataSource(getAudioFileUrl());
                } else {
                    audioPlayer.setDataSource(getContext(), getAudioFileUri());
                }

                audioPlayer.prepare();

                // This thread object will send update audio progress message to caller activity every 1 second.
                Thread updateAudioProgressThread = new Thread()
                {
                    @Override
                    public void run() {
                        while(true)
                        {
                            // Create update audio progress message.
                            Message updateAudioProgressMsg = new Message();
                            updateAudioProgressMsg.what = UPDATE_AUDIO_PROGRESS_BAR;

                            // Send the message to caller activity's update audio prgressbar Handler object.
                            audioProgressUpdateHandler.sendMessage(updateAudioProgressMsg);

                            // Sleep one second.
                            try {
                                Thread.sleep(1000);
                            }catch(InterruptedException ex)
                            {
                                ex.printStackTrace();
                            }
                        }
                    }
                };
                // Run above thread object.
                updateAudioProgressThread.start();
            }
        }catch(IOException ex)
        {
            ex.printStackTrace();
        }
    }

    // Destroy audio player.
    private void destroyAudioPlayer()
    {
        if(audioPlayer!=null)
        {
            if(audioPlayer.isPlaying())
            {
                audioPlayer.stop();
            }

            audioPlayer.release();

            audioPlayer = null;
        }
    }

    // Return current audio play position.
    public int getCurrentAudioPosition()
    {
        int ret = 0;
        if(audioPlayer != null)
        {
            ret = audioPlayer.getCurrentPosition();
        }
        return ret;
    }

    // Return total audio file duration.
    public int getTotalAudioDuration()
    {
        int ret = 0;
        if(audioPlayer != null)
        {
            ret = audioPlayer.getDuration();
        }
        return ret;
    }

    // Return current audio player progress value.
    public int getAudioProgress()
    {
        int ret = 0;
        int currAudioPosition = getCurrentAudioPosition();
        int totalAudioDuration = getTotalAudioDuration();
        if(totalAudioDuration > 0) {
            ret = (currAudioPosition * 100) / totalAudioDuration;
        }
        return ret;
    }
}

2.4 Layout Xml File.

activity_play_background_audio.xml

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <TextView
        android:id="@+id/audio_file_url_text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold"
        android:textSize="20dp" />

    <Button
        android:id="@+id/start_audio_in_background"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Play Audio In Background Service"
        android:textAllCaps="false"/>

    <Button
        android:id="@+id/pause_audio_in_background"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Pause Audio In Background Service"
        android:textAllCaps="false"/>

    <Button
        android:id="@+id/stop_audio_in_background"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Stop Audio In Background Service"
        android:textAllCaps="false"/>

    <ProgressBar
        android:id="@+id/play_audio_in_background_service_progressbar"
        style="@android:style/Widget.ProgressBar.Horizontal"
        android:max="100"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:visibility="invisible"/>

</LinearLayout>

2.5 Android Manifest Xml File.

The background service component must be declared in AndroidManifest.xml file. Because this example play a web audio from a url, so it need android.permission.INTERNET permission to be declared in this file also.

READ :   How To Start Android Service Automatically At Boot Time

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.dev2qa.example">

    <!-- Play web url audio file required permission. -->
    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
      
        <activity android:name=".audio.background.PlayBackgroundAudioActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name=".audio.background.AudioService"
            android:enabled="true"
            android:exported="true"></service>
    </application>

</manifest>

Reference

  1. Android Play Local / URL Audio With ProgressBar Example
  2. How To Create, Start, Stop Android Background Service
(Visited 3,440 times, 11 visits today)

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.