Building custom DataSource for ExoPlayer
By: Julien Salvi
Tags: Media Player, Android, AndroidDev, Exoplayer, Android Development

Photo by Kushagra Kevat on Unsplash

ExoPlayer is a very powerful library, developed and maintained by Google, for playing various video and audio content on Android. It also provides a large set of extension for using custom data source or supporting new formats. Let see how we can build our own extension by developing a custom DataSource for playing content from a SMB server.

What is an ExoPlayer DataSource?

With ExoPlayer, a DataSource is an interface that reads data from URI-identified resources, it allows to open a connection to read the specified data on your server by example. The library provides a default implementation for reading HTTP sources with HttpDataSource and you can find several extension that uses OkHttp or another for supporting RMTP (Real-Time Messaging Protocol). ExoPlayer provides a factory interface for building your instance of your custom DataSource with DataSource.Factory.

Let’s have a look at the structure of these two interfaces:

For building custom DataSource, the main focus will be on implementing the open() and read() functions. They are the keys methods for opening the connection and read the data from your source.

In the section below, let see how we can build a custom DataSource for reading data on a server that implements SMB (Server Message Block) network protocol.

Building SMB DataSource for ExoPlayer

What is Server Message Block (SMB) protocol?

SMB is a communication protocol for accessing shared files, printers or even serial ports on a given network. This protocol relies on lower-level protocols for transport. SMB is mostly used on Microsoft Windows computers.

So this protocol can be quite nice when you want to stream your own video from your SMB server on your device.

Let’s have a look at the scheme syntax of a SMB URL:

smb://[[[domain;]username[:password]@]server[:port]/[[share/[dir/]file]]][?param=value[param2=value2[...]]]

By example a SMB URL might be looking as following:

smb://user:pwd@192.168.0.1/share/dir/path/awesomeVideo.mkv

Implementing the SMB DataSource with SMBJ library

For opening the communication between our Android application and our server, we are going to use SMBJ Java library. It will allow us to open the connection, browse files and stream the content from the server.

But first, let’s implement the SmbDataSourceFactory that will allow us to create the instance of the SmbDataSource that will be injected in our player’s MediaSource.

Now, let’s focus on the implementation of the SmbDataSource itself. It may extend DataSource directly, or BaseDataSource if you want that some logic remains handled by ExoPlayer. In the constructor, we are going to get all we need for reading the remote file on the SMB server by extracting the data and credentials from the URL.

Extract SMB information

Once the data is extracted, the connection can be opened in order to read the input stream and get the data buffer that will be consumed by the video, audio or text renderers. Thanks to the SMBJ library we can easily access the file we want to stream and then we can get the input stream from that file to get the number of bytes that can be read.

After opening the connection and getting the byte buffer we want to read, we are going to implement the read() function for dispatching the number of bytes read.

In the end, we want to close the client and the input stream when it has reached the end of the file or when the user is stopping the playback of the video by example. To do so, we just need to override the close() method and actually close all the connections we opened before.

Now that we have our new custom DataSource for reading media content on a SMB server, we can use it and inject it while setting up the player. When a new URL is detected with the SMB format, we can create the MediaSource to be used by the player with the instance of our SmbDataSource.