Android SDK

Learn how to use the Uplynk Android Player Library.

Download

Download the latest SDK from the CMS by following the "Download Player SDK" link, which can be found in the lower left-hand corner, and then selecting "Android". Alternatively, contact Uplynk support to receive a link to the latest version of this library.

Android Compatibility

Supported Android versions:

Android Version Level of Support

2.3 Gingerbread

4.0 Ice Cream Sandwich

4.1 Jelly Bean

4.2 Jelly Bean

4.3 Jelly Bean

4.4 KitKat

Support for most major brands and chipsets.

5.x Lollipop

6.x Marshmallow

7.x Nougat

8.x Oreo

General compatibility via MediaCodec API.

Compatibility testing and support is limited to latest firmware for a given device.

API

The Uplynk Android Player API mirrors that of android.media.MediaPlayer [API Level 14] and generally allows for a direct replacement by swapping imports. This section describes Uplynk MediaPlayer-specific:

Interfaces

Support Classes

CaptionStyle

Name Description

TEXT_SIZE_XSMALL

50% of native size

TEXT_SIZE_SMALL

75% of native size

TEXT_SIZE_NORMAL

100% of native size

TEXT_SIZE_LARGE

150% of native size

TEXT_SIZE_XLARGE

200% of native size

EDGE_TYPE_NONE

No special edge type.

EDGE_TYPE_DROP_SHADOW

Drop shadow effect for caption text.

EDGE_TYPE_RAISED

Raised effect for caption text.

EDGE_TYPE_DEPRESSED

Depressed effect for caption text.

EDGE_TYPE_UNIFORM

Outline effect for caption text.

setBackgroundColor(int):void

Caption text background color in Android color hexadecimal format (0xaarrggbb).

Default value: 0xff000000 {*}

setCaptionPreviewText(int row, int column, String text):void

Sets the starting row (1 -15), starting column (1-32), and the text to be displayed as a Caption Preview.

setEdgeType(int):void

Edge effect from EDGE_TYPE constants. Default=EDGE_TYPE_NONE

setTextColor(int):void

Caption text color in Android color hexadecimal format (0xaarrggbb).

Default value: 0xffffffff {*}

setTextSize(int):void

Caption text size adjustment percentage as integer [50-200].

Default value: TEXT_SIZE_NORMAL or 100%

setTypeface(Typeface):void

Caption text font.

Default value: MONOSPACE

setWindowColor(int):void

Caption background area color in Android color hexadecimal format.

Default value: 0x00000000 {*}

Color values are expressed as android.graphics.Color packed integers.

CaptionEvent

Name Description

mode:CaptionMode

Returns mode in range UNKNOWN,POP_ON,ROLL_UP,PAINT_ON.

eventType:CaptionEventType

Returns event type in range TEXT,LINEBREAK,CLEAR.

rowCount:short

Returns the number of rows that should be used for painting text when mode==ROLL_UP.

rows:SparseArray<CaptionRow>

Returns a list of CaptionRow objects (populated when mode==POP_ON).

character:CaptionCharacter

Returns a single CaptionCharacter object.

CaptionEvent.CaptionCharacter

Name Description

character():char

Character

color():int

Color as 0xrrggbb

isItalic():boolean

True if character should be italicized.

isUnderlined():boolean

True if character should be underlined.

CaptionEvent.CaptionRow

Name Description

getRow():int

Row index

getColumn():int

Column index

getIndent():int

Column position offset

getText():String

Row text as a plain string

getCharacters():Vector

List of character objects with style attributes

MediaPlayer.UplynkAssetInfo

Name Description

getAssetID():String

Asset ID (GUID)

getOwner():String

User ID

getDescription:String

Content description as defined in the CMS.

isAudioOnly():boolean

Indicates if content only contains audio.

isAd():boolean

Indicates if content is flagged as an ad in the CMS.

hasError():boolean

If true, there was an error retrieving asset information.

getTvRating():int

TV rating as defined in the CMS.

getMovieRating():int

Movie rating as defined in the CMS.

getRatingFlags():int

Rating flags as defined in the CMS.

getMaxSlice():int

Gets the total number of slices.

getDuration():double

Length in milliseconds of content.

getSliceDuration():double

Length in milliseconds of each slice.

getThumbnailPrefix():String

URL thumbnail path prefix

MediaPlayer.UplynkID3

Name Description

getKey():String

ID3 tag name

getValue():String

ID3 tag value

MediaPlayer.UplynkMetadata

Name Description

getAssetID():String

Asset ID (GUID)

getRay():String

Ray Alpha Index (A-G)

getSliceIndex():String

Slice number in hex.

getSliceNumber():int

Slice number in decimal.

getAssetInfo():UplynkAssetInfo

UplynkAssetInfo object describing the current slice (can be NULL).

MediaPlayer.UplynkSegment

Defines a piece of a playlist. Use the offset for calculating the correct timecode for loading thumbnails.

Name Description

getType():char

Type flag of segment { A=Ad, C=Content }.

getDuration():double

Duration of the segment in seconds.

getOffset():double

Index offset from the beginning of the specified asset.

getAssetId():String

Asset ID

MediaPlayer.UplynkTrackInfo

Name Description

getType():char

Type Flag of Track { A=Audio, S=Subtitle }

getName():String

Track Name

getGroup():String

Track Group Name

getLang():String

Track Language

Methods

Method Description

getAudioTrackOptions():Vector<UplynkTrackInfo>

[Build 64]

Retrieves a list of audio tracks. May return an empty list when there are no alternate audio tracks available.

Valid Player States { PREPARED | PLAYING | PAUSED }

getDisplayRectForMaxDimensions(maxWidth, maxHeight):Rect

[Build 86]

Returns a Rect of the content dimensions with proper aspect ratio given a set of bounds.

getPlaybackBitrate():int

[Build 90]

Returns the current variant's reported bitrate in bps

selectAudioTrack(int):boolean

[Build 64]

Sets the target audio track index. zero is always the default audio track.

Valid Player States { PREPARED | PLAYING | PAUSED }

setContext(Context):void

Allows persisting bandwidth stats by writing to a file in the apps private storage.

setCaptionChannel(int):void

Sets the preferred caption channel [1-4].

setCaptionStyle(CaptionStyle):void

Sets the visual properties of the captions.

setMaxBitrate(int):void

Limits the variant selection by specified value in Kbps.

Example: 500=500Kbps streams or less

setCaptionsEnabled(boolean):void

Enables/disables the display of closed captions in configured container.

setCaptionLayoutContainer(RelativeLayout):void

Sets the target container that closed captions will be created in. The RelativeLayout is assumed to be directly over the video SurfaceView with matching dimensions.

setOnAssetBoundaryListener(OnAssetBoundaryListener):void

Register for Content Boundary Events that are triggered when content changes, such as entering or leaving ad break. Note: this event my be received twice, once with an Asset ID of the new asset and once with a null asset id to signify an ad marker.

setOnCaptionEventListener(OnCaptionEventListener):void

Register for Caption Events to receive caption text.

setOnID3MetadataListener(OnID3MetadataListener):void

Register for ID3 Metadata Events to receive name/value pairs.

setOnUplynkMetadataListener(OnUplynkMetadataListener):void

Register for Metadata Events that are fired for each slice.

setOnUplynkSegmentListener(OnUplynkSegmentListener):void

Register for Segment List Events that are fired during playlist updates.

setVolume(float leftVolume, float rightVolume):void

Scaler values normalized in range of 0.0 to 1.0.

Volume setting is local to player and does not affect device volume.

Class Methods

Class Methods Description

getDisplayRectForMaxDimensionsAndVideoDimensions(maxWidth, maxHeight, videoWidth, videoHeight):Rect

[Build 86]

Returns an aspect ratio constrained Rect for a given set of Max display bounds and content dimensions.

initSurfaceHolder(SurfaceHolder):void

Allows for configuration of a SurfaceHolder to render correctly with the current device hardware.

This must be called on the SurfaceHolder BEFORE passing the SurfaceHolder to a MediaPlayer instance via setDisplay(SurfaceHolder).

Closed Captions

Captions can be accessed either by allowing the MediaPlayer to display the captions or by registering an event listener to receive notifications (or both)

  1. Configure MediaPlayer to display the captions.

    1. Pass a RelativeLayout to the MediaPlayer via MediaPlayer.setCaptionLayoutContainer(RelativeLayout layout). The Container should be positioned over the MediaPlayer's SurfaceView and not allow touches.
    2. Enable the display by calling MediaPlayer.setCaptionsEnabled(boolean enabled).
  2. Register for caption events.

    1. Attach an event listener to the MediaPlayer via MediaPlayer.setOnCaptionEventListener(MediaPlayer.OnCaptionEventListener listener).
    2. Implement MediaPlayer.OnCaptionEventListener on your listener class (Activity).
    3. Override onCaptionEventListener(MediaPlayer mp, CaptionEvent cc) on your listener and implement logic to display the text supplied by the event.

Android Integration

Activity Setup

import com.uplynk.media.CaptionEvent;
import com.uplynk.media.CaptionEvent.CaptionEventType;
import com.uplynk.media.CaptionEvent.CaptionMode;
import com.uplynk.media.CaptionEvent.CaptionRow;
import com.uplynk.media.MediaPlayer;
import com.uplynk.media.MediaPlayer.UplynkAssetInfo;
import com.uplynk.media.MediaPlayer.UplynkID3;
import com.uplynk.media.MediaPlayer.UplynkMetadata;

public class MyVideoPlayerActivity extends Activity
	implements
		SurfaceHolder.Callback,
		MediaController.MediaPlayerControl,
		MediaPlayer.OnCompletionListener,
		MediaPlayer.OnErrorListener,
		MediaPlayer.OnSeekCompleteListener,
		MediaPlayer.OnPreparedListener,
		MediaPlayer.OnAssetBoundaryListener,
		MediaPlayer.OnCaptionEventListener,
		MediaPlayer.OnID3MetadataListener,
		MediaPlayer.OnUplynkMetadataListener,
		MediaPlayer.OnUplynkSegmentListener
{

    private MediaPlayer      _mp;
    private MediaController  _mc;
    private SurfaceView      _sv;
    private SurfaceHolder    _sh;
    ...

    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        ...
        _sv = (SurfaceView)this.findViewById(R.id.surfaceView);
        _sh = _sv.getHolder();
        // configure Surface Holder (required for certain devices)
        MediaPlayer.initSurfaceHolder(_sh);
        _sh.addCallback(this);
        ...
    }
}

Player Creation

private void playContent(final String url)
{
    if(_mp !=null)
    {
        _mp.release();
        _mp = null;
    }

    // Create a new media player
    _mp = new MediaPlayer();

    _mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
    _mp.setContext(this);     // allow persisting bandwidth stats (optional)
    //_mp.setMaxBitrate(1536);  // bandwidth limit in Kps (optional)

    // Attach Listeners
    _mp.setOnErrorListener(this);
    _mp.setOnCompletionListener(this);
    _mp.setOnSeekCompleteListener(this);
    _mp.setOnPreparedListener(this);
    _mp.setOnVideoSizeChangedListener(this);
    _mp.setOnID3MetadataListener(this);

    _mp.setOnUplynkMetadataListener(this);
    _mp.setOnCaptionEventListener(this);
    _mp.setOnAssetBoundaryListener(this);

    // Attach Caption container (optional)
    _mp.setCaptionsEnabled(true);
    _mp.setCaptionLayoutContainer((RelativeLayout)this.findViewById(R.id.ccContainer));

    // Set Caption Styles (optional)
    CaptionStyle style = new CaptionStyle();
    style.setBackgroundColor(0x3300ff00);
    style.setTextColor(0xffdddddd);
    style.setTextSize(CaptionStyle.TEXT_SIZE_SMALL);
    style.setEdgeType(CaptionStyle.EDGE_TYPE_DROP_SHADOW);
    style.setTypeface(Typeface.SANS_SERIF);
    _mp.setCaptionStyle(style);

    // Attach a MediaController (optional)
    _mc = new MediaController(this);
    _mc.setAnchorView(_sv);

    // Set the surface for the video output
    _mp.setDisplay(_sh); // must already be created
    _mp.setScreenOnWhilePlaying(true);

    try {
        _mp.setDataSource(url);
        _mp.prepareAsync(); // start asynchronous player preparation
    } catch (IllegalArgumentException e) {
        /* handle error */
    } catch (IllegalStateException e) {
        /* handle error */
    } catch (IOException e) {
        /* handle error */
    }
}

OnPrepared Handler

@Override
public void onPrepared(MediaPlayer mp)
{
    if(mp == _mp)
    {
        _mc.setMediaPlayer(this); // attach media controller (optional)
        //_mp.seekTo(20000); // set starting position in milliseconds if > 0 (optional)

        _mp.start(); // tell player to start playback
    }
}

OnUplynkMetadata Handler

@Override
public boolean onUplynkMetadata(MediaPlayer mp, UplynkMetadata metadata)
{
    Log.d(TAG, "MediaPlayer::onUplynkMetadata called (" + metadata.toString() + ")");
    return true;
}

OnID3Metadata Handler (Build 63)

@Override
public boolean onID3Metadata(MediaPlayer mp, UplynkID3 metadata)
{
    Log.d(TAG,String.format("MediaPlayer::onID3Metadata: [%s] %s",metadata.getKey(),metadata.getValue()));
    return true;
}

OnCaptionEvent Handler

@Override
public boolean onCaptionEvent(MediaPlayer mp, CaptionEvent event)
{
    Log.d(TAG, "MediaPlayer::onCaptionEvent called");

    // if POP_ON, render 'rows' data
    if( event.mode == CaptionMode.POP_ON)
    {
        // loop through all characters of all rows to render
        SparseArray<CaptionRow> rows = event.rows;
        for(int i=0;i<rows.size();++i)
        {
            CaptionEvent.CaptionRow row = rows.valueAt(i);
            // Log.i(TAG,String.format("CC [%d] {%d} %s",row.getRow(),(row.getColumn()+row.getIndent()),row.getText()));

            Vector<CaptionEvent.CaptionCharacter> characters = row.getCharacters();
            for(int x=0;x<characters.size();++x)
            {
                CaptionEvent.CaptionCharacter cc = characters.get(x);
                // Log.w(TAG,String.format("CC CHAR [%c]  color:%d  italic:%b  underlined:%b ",cc.character(), cc.color(), cc.isItalic(), cc.isUnderlined()));
                // handle character
            }
        }
    }
    // if ROLL_UP, render single character or handle other event type
    else if( event.mode == CaptionMode.ROLL_UP)
    {
        if(event.eventType == CaptionEventType.TEXT)
        {
            CaptionEvent.CaptionCharacter cc = event.character;
            // Log.d(TAG,String.format("CC %c",cc.character()));
            // render individual character
        }
        else if(event.eventType == CaptionEventType.LINEBREAK)
        {
            // line break so push content up one line and start new line
        }
        else if(event.eventType == CaptionEventType.CLEAR)
        {
            // clear all content
        }
    }
    return true;
}

OnAssetBoundary Handler

@Override
public void onAssetBoundary(MediaPlayer mp, String assetID)
{
    Log.i(TAG,"onAssetBoundaryListener: " + assetID);
}

SurfaceCreated Callback (Build 61)

// As of build 61 (2014.03.20), a surfaceDestroyed(...) callback will unbind the
// surface from the player to prevent memory leaks
// make sure to rebind the surface when it is recreated via it's surfaceCreated(...) callback
@Override
public void surfaceCreated(SurfaceHolder sh)
{
    Log.d(TAG, "surfaceCreated called");

    // need to re-attach surface
    if(_mp != null && sh == _sh)
    {
        _mp.setDisplay(_sh);
        _mp.setScreenOnWhilePlaying(true);
    }
}

Change Log / Version History

Version Description

v102b 2017.08.02

Fix to prevent possible crash related to getPlaybackBitrate() method

Enhanced compatibility with Android 8 (O) preview

v101 2017.06.07

Fix for Alternate Audio Switch Failure on Android 4.3 and lower

v100 2017.05.03

Fix for possible missing stream metadata on Android 4.4

Prevent possible Abort during OMXCodec creation on Android 4.4

Prevent possible crash/hang if calling .stop() or .reset() while player is still initializing

Fixes for Roll Up style captions

Support for Roll On style captions

v99 2016.11.30

Prevent possible crash if seeking while Video Decoder is reconfiguring

v98 2016.11.04

Fix possible crash when selecting alternate audio tracks

v97 2016.10.31

Fix for OMAP 4 Devices on Android 4.4

v96 2016.10.24

Fix for possible hang related to calling setDataSource while player is busy

Throw IllegalStateException from prepare / prepareAsync instead of crash if bad state or no datasource set

v95 2016.10.05

Fixes related to network error handling

Fixes related to quality selection of live streams

Fix possible blocking situation when calling .start() that my trigger an ANR

Fixes related to reported playhead position after seeking

Fixes related to Audio Only streams

Fix possible NPE crash in CaptionManager related to Caption Overlay View

Fix possible ANR during player stop related to hung system audio engine

v94 2016.08.11

Support for Android 7 (Nougat)

Fix incorrect quality switching in some cases on Live Streams

Fix possible deadlock situation when calling .start()

Reduced overall library bundle size

v93 2016.07.29

Fix possible crash related to some invalid or expired content urls

v92 2016.07.26

Fix for crash related to ads/slate with no audio on some devices

v91 2016.07.21

Fix for possible crash related to some audio track configurations

Tested on Android N Preview 5

v90 2016.07.15

Android N Preview 4

* Initial Support (may not be compatible with Preview 5 or Final release)

-API Addition:

MediaPlayer.getPlaybackBitrate():int returns the current variant's reported bitrate in bps

-Enhancements to general performance including stream start time reduction for Android 4.4+

-Add Support for Dolby Digital output for Android 5.0+ on supported devices

v89b 2016.04.14 (Hotfix)

Fix issue related to setting content start position

v89 2016.03.02

Prevent possible crashes related to using HTTPS content URLs

Prevent possible stream failure after a short connection loss/reconnect

Add Support for x86 Devices running Android 6.0

v88b 2016.01.18

Fix for possible long starting delay when playing content less than 4 seconds long

v87 2016.01.11

API Addition:

MediaPlayer(Map) to include custom HTTP headers on requests

* All headers names require "X-" prefix

v86 2015.12.11

Fix hasCaptions flag not being set on Android 5.0 and higher

Redraw captions when caption style is changed

Increase caption display duration

Prevent possible crash during a bad start related to audio system

Fix possible crash with quality change during a seek

Fixes related to time tracking when alternate audio track is enabled

API Addition: utility methods for calculating Aspect Ratio constrained display surface bounds

MediaPlayer.getDisplayRectForMaxDimensions(int maxWidth, int maxHeight): Rect

MediaPlayer::getDisplayRectForMaxDimensionsAndVideoDimensions(int maxWidth, int maxHeight, int videoWidth, int videoHeight): Rect

v85d 2015.10.26

Discontinuity handling fix for Android 4.4 and lower

v85c 2015.10.07

Memory Leak and Possible Deadlock fixes

v85b

Fix crash related to ID3 Tags with a Description Field

v85 2015.10.05

Support for Android 6 (Marshmallow)

MediaCodec implementation for use on Lollipop and higher

Video: Skip Non Key frames when restoring video surface to prevent failure on MediaTek devices and corruption on other devices

Enable Hardware Rendering on Lollipop with Broadcom chipset for FireTV Stick with Lollipop

Discontinuity Tracking enhancements

v84c 2015.07.22

Prevent video hesitation during ad break transitions (HW Rendering)

Fixes for some devices with Qualcomm chipset decoder that incorrectly adjust frame timestamps

Signal an Error Event and stop in the advent of a timing failure of video stream

Prevent possible hang when changing directly from one display surface to another

v83 2015.06.29

Fix possible crash when setting start position to within the first segment (~ 4 seconds)

Fix possible hang if stop() called while buffering

Fix possible quality degradation or failure with Hardware rendering after a resolution change on some devices

v82 2016.06.12

Fix possible loss of video when surface is removed and then reassigned to the player (Lollipop)

Prevent invalid decoder state if player is started before a surface is assigned (Lollipop)

Prevent decoder hang if buffer allocation fails during initialization

Fix for possible failure when moving from one display surface directly to a different surface (Lollipop)

Fix video flickering on Verizon Ellipsis 7 Tablet

Fix issue that could trigger a high quality stream on a slow connection

Allow quicker failure when device appears to be offline, instead of making multiple retries

v81 2016.06.12

Revised Input Buffer Allocation for Qualcomm chipsets to fix Snapdragon 400 chipset support

v80 2015.03.16

Fix for possible crash if content could not be loaded (invalid source / no internet connection)

Fix for crash related to TXXX ID3 tag parsing that include a description field + a value field

Fix to prevent possible Metadata Stream out of sync issue

v79 2015.03.05

Playback and Seek Stability Fixes for Android 5.0

Fix for incorrect onCompletion event signal while seeking

Support for Android 5.1

v78 2015.02.02

Fix for crash related to releasing the player while asset info fetch in progress

Fix possible hang if player was seeked and then reused with a different source

Fix possible hang when content could not be loaded (invalid source / no internet connection)

Fix crash on Android 2.3 related to audio engine not being released on previous playback

Fix ID3 Parsing Error related to PRIV tags

v77 2015.01.23

Fix invalid state if seekTo() called while paused

Fix invalid state if player is stopped while paused and then given a new source

v76 2015.01.21

Fix ID3 Parsing Error for long tag values

Fix hang when calling stop() while paused

v75 2015.01.15

Add Exynos Chipset Support on Android 5.0 / Lollipop (Nexus 10)

v74 2015.01.12

Support for Android 5 / Lollipop

Support for Hardware Rendering on Lollipop on some chipsets

* requires manually adjusting Surface Size to maintain proper aspect ratio

v73 2014.11.21

Fix for Closed Captions sometimes not being rendered after a seek to an earlier timecode

v72 2014.11.19

API Addition:

MediaPlayer.setSurface(Surface) can be used in place of setDisplay(SurfaceHolder) for using a TextureView for 4.x

Fixes to prevent crash when calling stop() or release() while player is still preparing

v71 2014.11.18

Fix for Closed Caption timing issue

v70 2014.10.16

Allow recovery of stream quality level after a forced downgrade due to high cpu load. Quality will recover after setting a new source or automatically after a short period of time on some devices.

v69 2014.10.10

Revised Decoder Handling for Broadcom AVC Decoder (Amazon FireTV Stick)

v68 2014.10.08

Added support for Broadcom AVC Decoder (Amazon FireTV Stick)

v67 2014.10.01

Fix for possible crash during stream shutdown

Added x86 support for Android 4.4.x (Galaxy Tab 3 10.1 w/ latest firmware)

v66 2014.09.24

Fix for Segment Downloader signaling onCompletion() instead of onError() after a download failure

v65 2014.09.23

Include armeabi-v7a architecture variant (can be excluded if armeabi is included)

Logging: All library tags are now prefixed with ?upLynk? or ?UL-?

Fix for possible crash related to setting initial playback position

Fix for possible crash related to quality selection on poor connections

Report error and shutdown if there is an audio or video decoder error instead of playing without the bad stream

v64 2014.08.21

New Feature: Alternate Audio Track Support (VOD)

API Addition:

MediaPlayer.getAudioTrackOptions():Vector<UplynkTrackInfo>

MediaPlayer.selectAudioTrack(int index)

MediaPlayer.OnUplynkSegmentListener Interface

MediaPlayer.setOnUplynkSegmentListener(OnUplynkSegmentListener listener)

Fix playback failure on Audio Only streams

Fix seek failure if the playhead was so near the content end that one but not all of the playback threads had exited

Fix for some Android 2.3 Devices with Secure Decoders not able to dynamically change quality levels

Fix NPE related to the caption container being destroyed while in use

More Information