Android Learning —— Multimedia Playback

Keywords: Mobile MediaPlayer Android network Database

Multimedia Player

brief introduction

Android's Multimedia Framework Pack supports playback of many common media types, allowing you to easily integrate audio, video and images into your applications.You can play audio or video media files that are stored in the resource files of your application.The application's resource files can be stand-alone files in the file system, or they can be obtained through a network connection - a stream of data, all of which use the MediaPlayer APIS.

**Note: ** You can only play audio data on standard output devices.Currently, the standard output device is a speaker or headset for a mobile device.You cannot play the sound file during the talk audio call.

Use MediaPlayer

One of the most important progressive aspects of the media framework is the MediaPlayer class, which can be accessed, decoded, and played with a small amount of settings.It supports a variety of media sources, such as:

  • Local Resources
  • Internal URI s, such as those you get from ContentResolver.
  • External URI (Streaming Media)

Permission Add

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

To play local video files, you need to create a raw folder under res to save the video files

    public void playFromRes(View view){
        MediaPlayer mp=MediaPlayer.create(this,R.raw.a1);
        mp.start();
    }

Play system video files

    public void playFromSys(View view){
        MediaPlayer mp=new MediaPlayer();
        String path= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)+"/2.mp4";
        try {
            mp.setDataSource(this, Uri.parse(path));//Setting up data streams
            mp.prepare();//Synchronous execution
            mp.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Play network video files

    public void playFromNet(View view){
        String path="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4";
        MediaPlayer mp=new MediaPlayer();
        try {
            mp.setDataSource(this,Uri.parse(path));
            mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    mp.start();
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Note: The prepare() call can be time consuming, as it may require acquiring open decoded media data and will take a long time to execute, then you cannot call it from your application's UI thread, otherwise it will cause the UI to hang.
Use Asynchronous Preparation
prepareAsync()
onPrepared() of MediaPlayer.OnPreparedListener

Management Status

MediaPlayer has an internal state because a specific operation is only valid in a specific state.If you perform an operation in the wrong state, the system may throw an exception or cause an unexpected behavior.

This state transition diagram clearly describes the states of MediaPlayer and lists the calling sequence of the main methods. Each method can only be used in certain states. IllegalStateException exceptions can be raised if the state of MediaPlayer is incorrect when used.

Idle status:

The MediaPlayer object is idle when a MediaPlayer object is created using the new() method or its reset() method is called.An important difference between the two methods is that if getDuration() and other methods are called in this state (equivalent to the incorrect timing of the call), OnErrorListener.onError() is triggered when the reset() method enters the idle state, and MediaPlayer enters the Error state; if a newly created MediaPlayer object is created, onError() is not triggered, nor is it entered the Error state.State.

End status:

The release() method allows you to enter the End state. As long as the MediaPlayer object is no longer used, it should be released by the release() method as soon as possible to release the related hardware and software component resources, some of which are only one (equivalent to a critical resource).If the MediaPlayer object enters the End state, it will not enter any other state.

Initialized status:

This state is relatively simple. MediaPlayer calls the setDataSource() method and enters the Initialized state, indicating that the file to be played is set at this time.

Prepared status:

After initialization, you also need to call prepare() or prepareAsync() methods, either synchronous or asynchronous, to indicate that MediaPlayer has no errors so far and can play files.

Preparing status:

This state is understandable, primarily in conjunction with prepareAsync(), which triggers OnPreparedListener.onPrepared() to enter the Prepared state if the asynchronous preparation is complete.

Started status:

Obviously, once MediaPlayer is ready, it can call the start () method so that MediaPlayer is in the Started state, indicating that MediaPlayer is playing the file.You can use isPlaying() to test if the MediaPlayer is in the Started state.Similarly, MediaPlayer can stay in Started state if it calls the seekTo() or start() method in this state.

Paused status:

MediaPlayer calls pause() method in Started state to pause MediaPlayer and enter Paused state. MediaPlayer calls start() again after pausing to continue playing MediaPlayer, go to Started state, and call seekTo() method when pausing state, which does not change state.

Stop status:

stop() can be called to stop MediaPlayer in either Started or Paused state, and MediaPlayer in Stop state needs to restart to its previous prepareAsync() and prepare() state in order to play back.

PlaybackCompleted status:

When the file has finished playing normally without setting up a loop, it enters the state and triggers the onCompletion() method of OnCompletionListener.You can call the start() method to play the file from scratch, stop() to stop the MediaPlayer, or seekTo() to relocate the playback location.

Error status:

If for some reason a MediaPlayer error occurs, it triggers the OnErrorListener.onError() event, at which point the MediaPlayer enters the Error state. It is important to catch and properly handle these errors, which can help us release related hardware and software resources in a timely manner and also improve the user experience.setOnErrorListener(android.media.MediaPlayer.OnErrorListener) allows you to set up the listener.If the MediaPlayer enters the Error state, it can be restored by calling reset(), which returns the MediaPlayer to the Idle state.

Refer to the blog for details: http://blog.sina.com.cn/s/blog_63f5ae1a0100zajv.html

Release MediaPlayer
MediaPlayer can consume a lot of system resources, so you should always take some extra steps to ensure that you don't hang too long on a MediaPlayer instance.When you are finished with MediaPlayer, you should always call release() to ensure that any system resources assigned to MediaPlayer are properly released.

Use Services to Control MediaPlayer

Simply put, it's background playback.Implement a MediaPlayer instance through a Service.
musicService

package com.example.mediaplay;

import android.annotation.SuppressLint;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayer;
import android.net.wifi.WifiManager;
import android.os.Environment;
import android.os.IBinder;
import android.os.PowerManager;

import java.io.IOException;

public class MusicService extends Service implements MediaPlayer.OnPreparedListener {
    public static final String ACTION_PLAY="com.example.ACTION_PLAY";
    public static final String ACTION_PAUSE="com.example.ACTION_PAUSE";
    public static final String ACTION_EXIT="com.example.ACTION_EXIT";
    private MediaPlayer mediaPlayer;
    private WifiManager.WifiLock lock;
    public MusicService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mediaPlayer=new MediaPlayer();
        mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
        //Keep wifi out of hibernation
        @SuppressLint("WifiManagerLeak") WifiManager wifiManager= (WifiManager) getSystemService(Context.WIFI_SERVICE);
        WifiManager.WifiLock lock=wifiManager.createWifiLock("mylock");
        lock.acquire();
        mediaPlayer.setOnPreparedListener(this);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        lock.release();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        String action=intent.getAction();
        if (ACTION_PLAY.equals(action)){
            mediaPlayer.reset();
            try {
                mediaPlayer.setDataSource(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)+"/2.mp4");
                mediaPlayer.prepareAsync();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else if (ACTION_PAUSE.equals(action)){
            if (mediaPlayer.isPlaying())mediaPlayer.pause();
        }else if (ACTION_EXIT.equals(action)){
            if (mediaPlayer.isPlaying())mediaPlayer.stop();
            mediaPlayer.release();
        }
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onPrepared(MediaPlayer mp) {
        mp.start();
    }
}

Main End

    public void play(View view){
        Intent intent=new Intent(this,MusicService.class);
        intent.setAction(MusicService.ACTION_PLAY);
        startService(intent);
    }

    public void pause(View view){
        Intent intent=new Intent(this,MusicService.class);
        intent.setAction(MusicService.ACTION_PAUSE);
        startService(intent);
    }

    public void exit(View view){
        Intent intent=new Intent(this,MusicService.class);
        intent.setAction(MusicService.ACTION_EXIT);
        startService(intent);
    }

Inventory File

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WAKE_LOCK"/>

		<service
            android:name=".MusicService"
            android:enabled="true"
            android:exported="true"
            android:process=":music">
            <intent-filter>
                <action android:name="com.example.ACTION_PLAY"/>
                <action android:name="com.example.ACTION_PAUSE"/>
                <action android:name="com.example.ACTION_EXIT"/>
            </intent-filter>
        </service>


Front Office Service
Adding methods to Service

	private void notification() {
        Notification.Builder builder=new Notification.Builder(this);
        builder.setTicker("My first music player");
        builder.setSmallIcon(R.mipmap.ic_launcher);
        builder.setContentTitle("My Music Player");
        builder.setContentInfo("Playing");
        PendingIntent pi=PendingIntent.getActivity(this,0,new Intent(this,Main3Activity.class),PendingIntent.FLAG_UPDATE_CURRENT);
        builder.setContentIntent(pi);
        NotificationManager nm= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        Notification notification=builder.build();

        startForeground(0,notification);
        nm.notify(0,notification);
    }

Handle Audio Focus

Call requestAudioFcus() from AudioManager;
The parameter focusChange tells you how the audio focus has changed:
AUDIOFOCUS_GAIN: You have gained audio focus
AUDIOFOCUS_LOSS: You have lost audio focus for a long time. You must stop all audio playback because it is anticipated that you may not be able to get audio focus for a long time, so this is a good place to clean up your resources. For example, you must release MediaPlayer.
AUDIOFOCUS_LOSS_TRANSIENT: You have temporarily lost focus on audio and will soon regain it. You must stop all audio playback, but you can keep your resources because you may regain focus soon.
AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: You temporarily lost the audio focus, but you are allowed to continue playing at low volume instead of stopping completely.

Add AudioManager.OnAudioFocusChangeListener interface
Override onAudioFocusChange method

@Override
    public void onAudioFocusChange(int focusChange) {
        switch (focusChange){
            case AudioManager.AUDIOFOCUS_GAIN:
                //To get focus
                initMediaPlayer();
                mediaPlayer.setVolume(1.0f,1.0f);
                break;
            case AudioManager.AUDIOFOCUS_LOSS:
                //Long Lost Focus
                if (mediaPlayer!=null){
                    if (mediaPlayer.isPlaying())mediaPlayer.stop();
                    mediaPlayer.release();
                }
                break;
            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                //Lose focus, but get it soon
                if (mediaPlayer!=null){
                    if (mediaPlayer.isPlaying())mediaPlayer.stop();
                }
                break;
            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                //Allow low volume playback
                if (mediaPlayer.isPlaying())mediaPlayer.setVolume(0.1f,0.1f);
                break;
        }
    }

And get focus in the onCreate method

		//Get Audio Focus
        AudioManager am= (AudioManager) getSystemService(AUDIO_SERVICE);
        am.requestAudioFocus(this,AudioManager.STREAM_MUSIC,AudioManager.AUDIOFOCUS_GAIN);

Encapsulate as a method call

		mediaPlayer=new MediaPlayer();

        mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
        //Keep WIFI working
        WifiManager wifiManager= (WifiManager)getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        lock=  wifiManager.createWifiLock("mylock");
        lock.acquire();
        mediaPlayer.setOnPreparedListener(this);

        notification();

Processing AUDIO_BECOMING_NOISY intent

Many good audio playback applications automatically stop playing when the sound changes to noise (output through an external speaker) at that time.For example, this may occur when the user suddenly disconnects the headset while listening to music with the headset.

Create a broadcast receiver

package com.example.mediaplay;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class MusicIntentReceiver extends BroadcastReceiver {
    private static final String action="android.media.AUDIO_BECOMING_NOISY";
    public MusicIntentReceiver(){

    }

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(action)){
            Intent intent1=new Intent(MusicService.ACTION_STOP);
            context.startService(intent1);
        }
    }
}

Register action in usicService

public static final String ACTION_STOP="com.example.ACTION_STOP";

//Add under onStartCommand method
else if (ACTION_STOP.equals(action)){
    if (mediaPlayer.isPlaying())mediaPlayer.stop();
}

Inventory File

		<receiver
            android:name=".MusicIntentReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.media.AUDIO_BECOMING_NOISY"/>
            </intent-filter>
        </receiver>

//In Service
<action android:name="com.example.ACTION_STOP" />

Get media from ContentResolver

Another useful feature of media playback applications is the ability to retrieve music that the user has stored on the device.You can do this by querying the media from ContentResolver:


The database file in the diagram is the database that stores pictures and media in the simulator.

public void queryMusic(View view){
    ContentResolver cr=getContentResolver();
    Cursor c=cr.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,null,null,null,null);
    if (c!=null){
        while (c.moveToNext()){
            String url=c.getString(c.getColumnIndex(MediaStore.Audio.Media.DATA));
            String displayName=c.getString(c.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME));
            String artist=c.getString(c.getColumnIndex(MediaStore.Audio.Media.ARTIST));
            String time=c.getString(c.getColumnIndex(MediaStore.Audio.Media.DURATION));
            System.out.println("Route:"+url);
            System.out.println("Song title:"+displayName);
            System.out.println("Singer:"+artist);
            System.out.println("Time:"+time);
            System.out.println("------------------");
        }
    }
}


Posted by gamer on Sat, 04 May 2019 09:40:38 -0700