본문으로 건너뛰기

Exoplayer Examples - Kotlin Android

ExoPlayer is an open-source media player library developed by Google. It provides an easy-to-use API that allows developers to play audio and video content in their Android applications. ExoPlayer is highly customizable and supports various media formats and protocols.

In this article, we will dive into the world of ExoPlayer and learn how to use it in our Android applications. We will cover the basics of ExoPlayer, its architecture, and how to integrate it into an Android application.

Prerequisites

Before we start, make sure you have the following installed:

  • Android Studio
  • Android SDK

Getting Started

To use ExoPlayer in our Android application, we need to add the following dependency to our project's build.gradle file:

implementation 'com.google.android.exoplayer:exoplayer:2.15.1'

ExoPlayer Architecture

ExoPlayer is built on top of the Android MediaCodec and MediaExtractor APIs. It consists of the following components:

  • ExoPlayer: The main entry point for using ExoPlayer. It manages the playback of media and provides an API for controlling playback.

  • MediaSource: A class that represents a media stream or file. It provides a way to create a media stream from a URI or a file.

  • Renderer: A class that renders media to the screen or the speakers. ExoPlayer has built-in renderers for audio and video.

  • TrackSelector: A class that selects the tracks to play. It can choose the best track based on the device's capabilities and the user's preferences.

  • LoadControl: A class that manages the buffering of media. It can adjust the buffer size based on the network conditions.

Creating an ExoPlayer Instance

To create an instance of ExoPlayer, we need to create a new instance of SimpleExoPlayer and pass it a DefaultTrackSelector and a DefaultLoadControl:

val player = SimpleExoPlayer.Builder(context)
.setTrackSelector(DefaultTrackSelector(context))
.setLoadControl(DefaultLoadControl())
.build()

Creating a MediaSource

To play a media file, we need to create a MediaSource object. ExoPlayer supports various media formats and protocols, including HLS, DASH, SmoothStreaming, MP3, MP4, and more.

Here's an example of how to create a MediaSource from a URI:

val uri = Uri.parse("https://example.com/media.mp4")
val mediaSource = ProgressiveMediaSource.Factory(DefaultDataSourceFactory(context))
.createMediaSource(uri)

Creating a Renderer

To render the media to the screen or the speakers, we need to create a Renderer object. ExoPlayer has built-in renderers for audio and video.

Here's an example of how to create a Renderer for video:

val videoRenderer = MediaCodecVideoRenderer(
context,
MediaCodecSelector.DEFAULT,
MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
)

Adding a MediaSource to ExoPlayer

To add a MediaSource to ExoPlayer, we need to call the prepare method and pass it the MediaSource object:

player.prepare(mediaSource)

Playing and Pausing Media

To start playing the media, we need to call the play method:

player.play()

To pause the media, we need to call the pause method:

player.pause()

Releasing ExoPlayer

When we're done playing the media, we need to release the SimpleExoPlayer instance:

player.release()

More Examples

This sectuon will explore simple step by step Exoplayer Examples. It will teach you how to use it to play audio and video. We do this via simple isolated examples created for beginners.

Let's now look at some examples.

Example 1: Simple Exoplayer Example

A simple Exoplayer Example project.

Step 1: Create Project

Start by creating an empty Android Studio project.

Step 2: Dependencies

Add Exoplayer as a dependency in your app/build.gradle:

    implementation 'com.google.android.exoplayer:exoplayer:2.8.4'

If Java8 is not enabled please enable it.

Sync.

Step 3: Design Layout

Design a layout to represent the media player component, with buttons for starting, stopping etc as shown below:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">

<LinearLayout
android:id="@+id/player"
android:layout_width="match_parent"
android:layout_height="wrap_content"

android:layout_alignParentBottom="true"
android:background="@color/colorPrimaryDark"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">

<TextView
android:id="@+id/tv_audioname"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:visibility="gone"
android:gravity="center"
android:textColor="@android:color/black"/>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal">

<!-- <ImageButton-->
<!-- android:id="@+id/amount"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="match_parent"-->
<!-- android:layout_weight="1"-->
<!-- android:background="@android:color/transparent"-->
<!-- android:text="Button" />-->

<TextView
android:id="@+id/timee"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="10dp"
android:text="0:00" />

<!-- rewind-->
<ImageButton
android:id="@+id/btn_prev"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@android:color/transparent"
app:srcCompat="@drawable/ic_fast_rewind_black_24dp" />

<!-- play/pause-->

<Button
android:id="@+id/btn_pauseee"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@android:color/transparent"
android:text="Play" />

<!-- fast forward-->
<ImageButton
android:id="@+id/btn_ffwddd"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@android:color/transparent"
app:srcCompat="@drawable/ic_fast_forward_black_24dp" />

<!-- <ImageButton-->
<!-- android:id="@+id/button"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="match_parent"-->
<!-- android:layout_weight="1"-->
<!-- android:background="@android:color/transparent" />-->

<TextView
android:id="@+id/durationnn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="10dp"
android:text="0:00" />

</LinearLayout>

<SeekBar
android:id="@+id/seekBar"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_marginBottom="10dp"
android:visibility="visible"/>
</LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Step 4: Write Code

Below is the code:

MainActivity.java

package com.sarthak.exoplayerdemo;

import androidx.appcompat.app.AppCompatActivity;

import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.TextView;

import com.google.android.exoplayer2.DefaultRenderersFactory;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelector;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.util.Util;

public class MainActivity extends AppCompatActivity {

SimpleExoPlayer simpleExoPlayer;
Boolean isPlaying;
SeekBar seekBar;
TextView time,duration;
Handler handler;
Runnable runnable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
isPlaying = false;

seekBar = findViewById(R.id.seekBar);
time = findViewById(R.id.timee);
duration = findViewById(R.id.durationnn);
setupPlayer();
final Button button = findViewById(R.id.btn_pauseee);
ImageButton button1 = findViewById(R.id.btn_ffwddd);
ImageButton button2 = findViewById(R.id.btn_prev);

handler = new Handler();

button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
simpleExoPlayer.seekTo(simpleExoPlayer.getCurrentPosition() + 5000);
seekBar.setProgress(Integer.parseInt(String.valueOf(simpleExoPlayer.getCurrentPosition() + 5000)));
seekBar.setMax(Integer.parseInt(String.valueOf(simpleExoPlayer.getDuration())));
changeSeekBar();
setTime();
}
});

button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
simpleExoPlayer.seekTo(simpleExoPlayer.getCurrentPosition() - 5000);
seekBar.setProgress(Integer.parseInt(String.valueOf(simpleExoPlayer.getCurrentPosition() - 5000)));
seekBar.setMax(Integer.parseInt(String.valueOf(simpleExoPlayer.getDuration())));
changeSeekBar();
setTime();
}
});

button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
seekBar.setMax(Integer.parseInt(String.valueOf(simpleExoPlayer.getDuration())));
changeSeekBar();
setTime();
if(!isPlaying){

simpleExoPlayer.setPlayWhenReady(true);
isPlaying = true;
button.setText("Pause");
seekBar.setProgress(Integer.parseInt(String.valueOf(simpleExoPlayer.getCurrentPosition())));

}
else if(isPlaying){
simpleExoPlayer.setPlayWhenReady(false);
//simpleExoPlayer.release();
button.setText("Play");
isPlaying = false;
seekBar.setProgress(Integer.parseInt(String.valueOf(simpleExoPlayer.getCurrentPosition())));

}
}
});

seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if(fromUser){
simpleExoPlayer.seekTo(progress);
setTime();
}
}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {

}

@Override
public void onStopTrackingTouch(SeekBar seekBar) {

}
});

}

private void setupPlayer(){

DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(this,null,DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF);

//BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(); //Global

TrackSelector trackSelector = new DefaultTrackSelector();//(new AdaptiveTrackSelection.Factory(renderersFactory));//global

simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(renderersFactory,trackSelector); //Global

//final DefaultHttpDataSourceFactory httpDataSourceFactory = new DefaultHttpDataSourceFactory("exoplayer_audio");//Global
//final ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();//Global
//MediaSource mediaSource = new ExtractorMediaSource(uri, httpDataSourceFactory, extractorsFactory, null, null);//Local

Uri uri = Uri.parse("http://awscdn.podcasts.com/Max-Weber-Authority-Power-Theory-dc90.mp3");
String userAgent = Util.getUserAgent(this,"Sunokitaab");
ExtractorMediaSource mediaSource =new ExtractorMediaSource(uri,
new DefaultDataSourceFactory(this,userAgent),
new DefaultExtractorsFactory(),
null,
null);

simpleExoPlayer.prepare(mediaSource);//Local
//simpleExoPlayer.setPlayWhenReady(true);//Local
//setTime();
}

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

@Override
protected void onPause() {
// simpleExoPlayer.setPlayWhenReady(false);
simpleExoPlayer.release();
super.onPause();
}
private void setTime() {

if(simpleExoPlayer!=null) {

long songCurrentTime = simpleExoPlayer.getCurrentPosition();
long songTotalTime = simpleExoPlayer.getDuration();

long secondT = (songCurrentTime / 1000) % 60;
long minuteT = (songCurrentTime / (1000 * 60)) % 60;

long secondD = (songTotalTime / 1000) % 60;
long minuteD = (songTotalTime / (1000 * 60)) % 60;

String timerD = String.format("%02d:%02d", minuteD, secondD);
String timerT = String.format("%02d:%02d", minuteT, secondT);

time.setText("" + String.valueOf(timerT));
duration.setText("" + String.valueOf(timerD));
}

}

private void changeSeekBar() {

if(simpleExoPlayer!=null){
seekBar.setProgress(Integer.parseInt(String.valueOf(simpleExoPlayer.getCurrentPosition())));
runnable = new Runnable() {
@Override
public void run() {
changeSeekBar();
setTime();
}
};
handler.postDelayed(runnable,1000);
}
}
}

Run

Copy the code or download it in the link below, build and run.

Reference

Here are the reference links:

NumberLink
1.Download Example
2.Follow code author

Conclusion

ExoPlayer is a powerful media player library that provides an easy-to-use API for playing audio and video content in Android applications. In this article, we learned how to create an instance of ExoPlayer, create a MediaSource object, create a Renderer object, add a MediaSource to ExoPlayer, and play and pause media. With this knowledge, you can now integrate ExoPlayer into your Android applications and provide a seamless media playback experience to your users.