Wednesday, February 7, 2024

Android java: Tutorial MediaPlayer and Media3 ExoPlayer

Android Studio Hedgehog | 2023.1.2

Note: For personal reference using MediaPlayer and Media3 ExoPlayer in java

build.gradle.kts (Module: app)

dependencies {
    ....
    implementation("androidx.media3:media3-exoplayer:1.2.1") // ExoPlayer
    implementation("androidx.media3:media3-common:1.2.1") // setAudioAttributes; MediaItem
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <uses-permission android:name="android.permission.INTERNET" />
...

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">
    <androidx.appcompat.widget.AppCompatButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="MediaPlayer"
        android:id="@+id/b_mediaplayer"
        />
    <androidx.appcompat.widget.AppCompatButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ExoPlayer"
        android:id="@+id/b_exoplayer"
        />
</androidx.appcompat.widget.LinearLayoutCompat>

MyExoPlayer.java

package com.dedetok.tutorialexoplayer;

import android.content.Context;
import android.util.Log;
import androidx.media3.common.MediaItem;
import androidx.media3.exoplayer.ExoPlaypackage com.dedetok.tutorialexoplayer;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatButton;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    MyMediaPlayer myMediaPlayer;
    MyExoPlayer myExoPlayer;

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

        myMediaPlayer = new MyMediaPlayer();
        myExoPlayer = new MyExoPlayer(this);

        String myRadioUrl = "https://stream-node1.rri.co.id/streaming/25/9025/rrijakartapro1.mp3";
        //String myRadioUrl = "http://cast1.my-control-panel.com/proxy/radioso1/stream";

        AppCompatButton bMediaPlayer = findViewById(R.id.b_mediaplayer);
        bMediaPlayer.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                myExoPlayer.stop();
                myMediaPlayer.play(myRadioUrl);
            }
        });

        AppCompatButton bExoPlayer = findViewById(R.id.b_exoplayer);
        bExoPlayer.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                myMediaPlayer.stop();
                myExoPlayer.play(myRadioUrl);
            }
        });
    }
}er;

public class MyExoPlayer {
    // API level 23 / Android N / Android 6.0
    ExoPlayer myPlayer;

    public MyExoPlayer(Context appContext) {
        myPlayer = new ExoPlayer.Builder(appContext).build();
    }

    public void play(String myRadioUrl) {
        if (myPlayer.isPlaying()) {
            myPlayer.stop();
            Log.e("dedetok", "ExoPlaayer playing Stop"); // debug
        } else {
            try {
                Log.e("dedetok", "ExoPlaayer playing " + myRadioUrl); // debug
                MediaItem myRadio = MediaItem.fromUri(myRadioUrl);
                myPlayer.setMediaItem(myRadio);
                myPlayer.prepare();
                myPlayer.play();
            } catch (IllegalArgumentException e) {
                Log.e("dedetok", "ExoPlayer IllegalArgumentException " + e.getMessage()); // debug
            }
        }
    }

    public void stop() {
        myPlayer.stop();
    }

    public void release() {
        myPlayer.release();
        myPlayer=null;
    }
}

MyMediaPlayer.java

package com.dedetok.tutorialexoplayer;

import android.media.AudioAttributes;
import android.media.MediaPlayer;
import android.util.Log;
import java.io.IOException;

public class MyMediaPlayer implements MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener {
    MediaPlayer myPlayer;

    boolean isPrepared= false;

    public MyMediaPlayer() {
        myPlayer = new MediaPlayer();
    }

    public void play(String myRadioUrl) {
        if (myPlayer.isPlaying()) {
            myPlayer.stop();
            myPlayer.reset();
            Log.e("dedetok", "MediaPlayer Stop"); // debug
        } else {
            Log.e("dedetok", "MediaPlayer playing " + myRadioUrl); // debug
            myPlayer.setOnPreparedListener(this);
            myPlayer.setAudioAttributes(
                    new AudioAttributes.Builder()
                            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                            .setUsage(AudioAttributes.USAGE_MEDIA)
                            .setLegacyStreamType(AudioAttributes.USAGE_MEDIA)
                            .build()
            );
            myPlayer.setOnErrorListener(this);
            try {
                myPlayer.setDataSource(myRadioUrl);
                isPrepared=true;
                myPlayer.prepareAsync();
            } catch (IOException e) {
                Log.e("dedetok", "IOException " + e.getMessage()); // debug
            } catch (IllegalArgumentException e) {
                Log.e("dedetok", "IllegalArgumentException " + e.getMessage()); // debug
            }
        }
    }

    @Override
    public void onPrepared(MediaPlayer mediaPlayer) {
        /*
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (mediaPlayer.getDrmInfo() != null) {
                myPlayer.prepareDrm();
                //myPlayer.getKeyRequest();
                //myPlayer.provideKeyResponse();
            }
        }

         */
        myPlayer.start();
        isPrepared=false;
    }

    public void stop() {
        if (!isPrepared) {
            myPlayer.stop();
            myPlayer.reset();
            isPrepared = false;
        } else {
            myPlayer.reset();
            isPrepared = false;
        }
    }

    @Override
    public boolean onError(MediaPlayer mediaPlayer, int what, int extra) {
        String tmp="";
        if (what == MediaPlayer.MEDIA_ERROR_UNKNOWN)
            tmp = "MediaPlayer.MEDIA_ERROR_UNKNOWN";
        if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED)
            tmp = "MediaPlayer.MEDIA_ERROR_SERVER_DIED";
        if (extra == MediaPlayer.MEDIA_ERROR_IO)
            tmp+=" MediaPlayer.MEDIA_ERROR_IO";
        if (extra == MediaPlayer.MEDIA_ERROR_MALFORMED)
            tmp+=" MediaPlayer.MEDIA_ERROR_MALFORMED";
        if (extra == MediaPlayer.MEDIA_ERROR_UNSUPPORTED)
            tmp+=" MediaPlayer.MEDIA_ERROR_UNSUPPORTED";
        if (extra == MediaPlayer.MEDIA_ERROR_TIMED_OUT)
            tmp+=" MediaPlayer.MEDIA_ERROR_TIMED_OUT";

        Log.e("dedetok", "OnErrorListener " + tmp); // debug
        myPlayer.reset();
        isPrepared=false;
        return true;
    }

    public void release() {
        myPlayer.release();
        myPlayer=null;
    }
}

MainActivity.java

package com.dedetok.tutorialexoplayer;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatButton;
import android.os.Build;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    MyMediaPlayer myMediaPlayer;
    MyExoPlayer myExoPlayer;
    int buildVersion=0;
    /*
     * ## activity life cycle 1 ##
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        buildVersion = Build.VERSION.SDK_INT; // get android version from device

        String myRadioUrl = "https://stream-node1.rri.co.id/streaming/25/9025/rrijakartapro1.mp3";
        //String myRadioUrl = "http://cast1.my-control-panel.com/proxy/radioso1/stream";

        AppCompatButton bMediaPlayer = findViewById(R.id.b_mediaplayer);
        bMediaPlayer.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                myExoPlayer.stop();
                myMediaPlayer.play(myRadioUrl);
            }
        });

        AppCompatButton bExoPlayer = findViewById(R.id.b_exoplayer);
        bExoPlayer.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                myMediaPlayer.stop();
                myExoPlayer.play(myRadioUrl);
            }
        });
    }

    /*
     * ## activity life cycle 2 ##
     */
    @Override
    protected void onStart() {
        super.onStart();
        // Android N Android 7
        if (buildVersion>= Build.VERSION_CODES.N) {
            myMediaPlayer = new MyMediaPlayer();
            myExoPlayer = new MyExoPlayer(this);
        }
    }

    /*
     * ## activity life cycle 3 ##
     */
    @Override
    protected void onResume() {
        super.onResume();
        // Android N Android 7
        if (buildVersion< Build.VERSION_CODES.N) {
            myMediaPlayer = new MyMediaPlayer();
            myExoPlayer = new MyExoPlayer(this);
        }
    }

    /*
     * ## activity life cycle 4 ##
     */
    @Override
    protected void onPause() {
        if (buildVersion<Build.VERSION_CODES.N) {
            myMediaPlayer.release();
            myMediaPlayer=null;
            myExoPlayer.release();
            myExoPlayer=null;
        }
        super.onPause();
    }

    /*
     * ## activity life cycle 5 ##
     */
    @Override
    protected void onStop() {
        if (buildVersion>=Build.VERSION_CODES.N) {
            myMediaPlayer.release();
            myMediaPlayer=null;
            myExoPlayer.release();
            myExoPlayer=null;
        }
        super.onStop();
    }

    /*
     * ## activity life cycle 6 ##
     */

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}

Pron using ExoPlayer:

  1. ExoPlayer can handle https media streaming for self signing sertificate but MediaPlayer can not.
  2. Handing media streaming in ExoPlayer uses less code then MediaPlayer.

Cons using ExoPlayer

  • ExoPlayer required minimum API level 23 / Android N / Android 6.0


No comments:

Post a Comment