How to Build a Simple RTMP Server and an Android RTMP Client with ExoPlayer2!

Shubham Kumar Gupta
4 min readDec 18, 2023

Hi, Welcome to a step-by-step guide on creating a basic RTMP (Real-Time Messaging Protocol) server and developing an Android RTMP client using ExoPlayer2. By the end of this tutorial, you’ll have a functional system that allows you to stream video from a server to your Android device seamlessly.

Introduction

RTMP is a widely-used protocol for high-performance transmission of audio, video, and data over the internet. It’s commonly used in live streaming scenarios, providing low latency and efficient data delivery. This tutorial will walk you through the process of setting up an RTMP server using Node Media Server and creating an Android RTMP client using ExoPlayer2.

Setting Up the RTMP Server

Step 1: Install Node Media Server

To get started, install the Node Media Server by executing the following command in your terminal:

npm i node-media-server

Step 2: Configure the Server (app.js)

Create a file named app.js and add the following JavaScript code to configure the RTMP server:

const NodeMediaServer = require('node-media-server');

const config = {
rtmp: {
port: 1935,
chunk_size: 60000,
gop_cache: true,
ping: 30,
ping_timeout: 60
},
http: {
port: 8000,
allow_origin: '*'
}
};
var nms = new NodeMediaServer(config);
nms.run();

Run the server using:

node app.js

Step 3: Stream Video

Download a video file (e.g., test_video.mp4) and use the following command to start streaming:

ffmpeg -re -i test_video.mp4 -c copy -f flv rtmp://localhost/live/test

Visit the admin interface at http://localhost:8000/admin/ to monitor the server.

Building the Android RTMP Client with ExoPlayer2

Now that we have our RTMP server up and running, let’s delve into creating an Android application to consume the streamed content using ExoPlayer2. ExoPlayer is a powerful media player library for Android that supports various audio and video formats, including RTMP streams.

Step 1: Import ExoPlayer Dependency

Begin by adding the necessary ExoPlayer dependencies to your Android project’s build.gradle file. These dependencies include the ExoPlayer core, UI components, and the RTMP extension:

// exoplayer
def exoplayer_version = "2.18.2"
implementation "com.google.android.exoplayer:exoplayer-core:$exoplayer_version"
implementation "com.google.android.exoplayer:exoplayer-ui:$exoplayer_version"
implementation "com.google.android.exoplayer:extension-rtmp:$exoplayer_version"

Ensure that your project is synchronized to fetch these dependencies.

Step 2: Design the User Interface

Craft a user-friendly layout in the activity_main.xml file, incorporating an EditText for entering the RTMP URL and a Button to initiate playback:

<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent" />

<EditText
android:id="@+id/etRtmpUrl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="rtmp://"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:minHeight="48dp"
android:layout_marginLeft="48dp"
android:layout_marginRight="48dp" />
<Button
android:id="@+id/playBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/etRtmpUrl"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginTop="10dp"
android:enabled="false"
android:text="play" />

This interface provides users with an intuitive means to input the RTMP URL and initiate playback.

Step 3: Implement MainActivity

In your MainActivity class, handle the button click event to open the PlayerFragment:

binding.playBtn.setOnClickListener {
val playerFragment = PlayerFragment.newInstance()
playerFragment.arguments = getBundleArguments()
val transactionManager = supportFragmentManager.beginTransaction()
transactionManager.add(R.id.fragmentContainer, playerFragment)
transactionManager.addToBackStack("PLAYER_FRAGMENT")
transactionManager.commit()
}

/**
* get argument bundle
*/
private fun getBundleArguments(): Bundle {
return Bundle().apply {
putString("url", binding.etRtmpUrl.text.toString())
}
}

This code ensures that clicking the button dynamically opens the PlayerFragment with the provided RTMP URL (your IP Address).

Step 4: Implement PlayerFragment

In your PlayerFragment, initialize and play the RTMP video using ExoPlayer2:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initializePlayer()
playVideo()
exoPlayer.playWhenReady = true
exoPlayer.prepare()
}

/**
* setup ExoPlayer
*/
private fun initializePlayer() {
exoPlayer = ExoPlayer.Builder(requireContext())
.build()
binding.playerView.player = exoPlayer
binding.playerView.setShowBuffering(SHOW_BUFFERING_ALWAYS)
}

/**
* Play RTMP
*/
private fun playVideo() {
val videoSource = ProgressiveMediaSource.Factory(RtmpDataSource.Factory())
.createMediaSource(MediaItem.fromUri(Uri.parse(url)))
exoPlayer.setMediaSource(videoSource)
}

These functions are crucial for setting up and initiating playback using ExoPlayer2 within the PlayerFragment.

Step 5: Player Fragment Layout

Finally, design the layout for the PlayerFragment:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:keepScreenOn="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.exoplayer2.ui.PlayerView
android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@android:color/transparent"
android:fitsSystemWindows="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:resize_mode="zoom"
app:shutter_background_color="@android:color/transparent"
app:surface_type="texture_view"
app:use_artwork="false" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

This layout ensures a seamless and visually appealing video playback experience within the PlayerFragment.

Conclusion

With these steps completed, we’ve successfully integrated ExoPlayer2 into your Android application, creating a fully functional RTMP client.

Now your Android application is now equipped to stream RTMP content effortlessly. Feel free to run your app and explore the seamless RTMP video streaming capabilities on your Android device.

source: https://github.com/illuspas/Node-Media-Server
git: https://github.com/gptshubham595/RTMP-ExoPlayer

--

--