FastPix player for Android
Integrate FastPix Android Player SDK for Media3-based video streaming with security and analytics.
The FastPix Android Player SDK is a full-featured, Media3-based playback library for Android apps. Built on top of ExoPlayer, it supports live and on-demand video streaming, playback security, analytics, track switching, and resolution control, giving you everything you need to deliver reliable, branded, and insight-rich video playback inside your Android applications.
You can use the GitHub repository for FastPix Android Player.
Prerequisites
Before you start, make sure you meet the following development and FastPix setup requirements.
Android environment
- Android Studio: Arctic Fox or later
- Android SDK: Version 24+
- FastPix Player dependency for Player
- FastPix ExoPlayer SDK (Media3-compatible) as a dependency
- GitHub Personal Access Token (PAT) for private Maven access
FastPix requirements
Complete the following setup steps in the FastPix Dashboard before integrating the SDK:
- Login to FastPix Dashboard: Go to dashboard.fastpix.io and sign in.
- Create Media: Use the UI or API to create a media asset (via push or pull URL).
- Get Playback ID: Go to View Media, select your uploaded file, and copy the
playbackId. - Use the Playback ID: This will be required to generate the playback URL in your app.
Install and configure the SDK
Open your android studio project
Open the project where you want to integrate the SDK.
Add the FastPix player SDK dependency
Navigate to your app-level build.gradle file (or build.gradle.kts if using Kotlin DSL) and add the following under the dependencies section:
dependencies {
// Check for latest version
implementation("io.fastpix.player:android:1.0.9")
}Add the GitHub Maven repository
Navigate to your settings.gradle (or settings.gradle.kts) file. You will need a GitHub Personal Access Token (PAT) to access the private Maven package.
Recommended: Load credentials from
local.propertiesso you do not hardcode secrets.
Add the following lines inside the repositories section:
repositories {
maven {
url = uri("https://maven.pkg.github.com/FastPix/fastpix-android-player")
credentials {
gpr.user=<your_github_username>
gpr.key=<your_github_pat>
}
}
}Sync your project with gradle files
Click Sync Now in the notification bar to download and integrate the FastPix Player SDK. Once the dependency is added, you can use the FastPix Player SDK module in any part of your Android project.
Import the SDK
Required imports
import io.fastpix.media3.PlayerView
import io.fastpix.media3.PlaybackListener
import io.fastpix.media3.core.FastPixPlayer
import io.fastpix.media3.core.PlaybackResolution
import io.fastpix.media3.core.RenditionOrder
import io.fastpix.media3.core.StreamType
import androidx.media3.common.MediaItem
import androidx.media3.common.PlaybackExceptionGlobal declarations
You can either:
- Use
PlayerViewonly (it auto-creates aFastPixPlayerwith default settings), or - Create a configured
FastPixPlayeryourself (loop, autoplay, seek preview, analytics, etc.) and attach it toPlayerView.
A global declaration ensures these objects can be accessed throughout the lifecycle of your Activity/Fragment.
class CustomizedPlayerActivity : AppCompatActivity() {
private lateinit var binding: ActivityCustomizedPlayerBinding
private val playerView get() = binding.playerView
private var player: FastPixPlayer? = null
private lateinit var playbackListener: PlaybackListener
}Activity setup with playback
The following example demonstrates a complete Activity setup including player initialization, listener registration, and resource cleanup:
import io.fastpix.media3.PlayerView
import io.fastpix.media3.PlaybackListener
import io.fastpix.media3.core.FastPixPlayer
import io.fastpix.media3.core.PlaybackResolution
import androidx.media3.common.MediaItem
import androidx.media3.common.PlaybackException
class CustomizedPlayerActivity : AppCompatActivity() {
private lateinit var binding: ActivityCustomizedPlayerBinding
private val playerView get() = binding.playerView
private var player: FastPixPlayer? = null
private lateinit var playbackListener: PlaybackListener
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityCustomizedPlayerBinding.inflate(layoutInflater)
setContentView(binding.root)
// Create a configured player (optional; PlayerView can also auto-create one).
player = FastPixPlayer.Builder(this)
.setAutoplay(true)
.setLoop(false)
.build()
playerView.player = player
}
override fun onStart() {
super.onStart()
startPlayback()
}
private fun startPlayback() {
playbackListener = object : PlaybackListener {
override fun onPlay() {}
override fun onPause() {}
override fun onPlaybackStateChanged(isPlaying: Boolean) {}
override fun onError(error: PlaybackException) {}
}
player?.addPlaybackListener(playbackListener)
// Option A: Direct URL playback
// player?.setMediaItem(MediaItem.fromUri("https://example.com/video.m3u8"))
// Option B: FastPix playback via playbackId (recommended)
player?.setFastPixMediaItem {
playbackId = "YOUR_PLAYBACK_ID"
maxResolution = PlaybackResolution.FHD_1080
// playbackToken = "YOUR_PLAYBACK_TOKEN" // optional (secure playback)
}
}
override fun onDestroy() {
super.onDestroy()
player?.removePlaybackListener(playbackListener)
if (isFinishing) {
// Forces release even if config-change retention is enabled on the view.
playerView.release()
}
}
}Key points about this setup:
CustomizedPlayerActivityuses view binding (ActivityCustomizedPlayerBinding) to accessPlayerViewfrom the layout.- A
FastPixPlayerinstance is created once and attached toPlayerView. - A
PlaybackListenerobserves playback state and errors. setFastPixMediaItem { ... }generates the playback URL usingplaybackIdplus optional parameters.- Call
playerView.release()inonDestroy()when the Activity is finishing to release resources.
Playback setup and use cases
The SDK supports several playback configurations depending on your security, quality, and routing requirements. The following sections cover each major scenario.
Public media playback (with stream type)
private fun startPlayback() {
player?.setFastPixMediaItem {
playbackId = "YOUR_PLAYBACK_ID" // mandatory
// streamType = StreamType.onDemand // reserved for future use
}
}Stream type notes:
setFastPixMediaItem { playbackId = ... }resolves a FastPix HLS stream URL:https://stream.fastpix.io/{playbackId}.m3u8- If you already have a playback URL (VOD or live), use direct URL playback via
setMediaItem(MediaItem.fromUri(url)). StreamTypeis currently included in the builder for API compatibility but is not yet applied to the resolved URL in this SDK version.
Secure playback (token-based)
private fun startPlayback() {
player?.setFastPixMediaItem {
playbackId = "YOUR_PLAYBACK_ID" // mandatory
playbackToken = "SET_PLAYBACK_TOKEN" // optional
}
}Token benefits:
- Unique playback ID: Identifies each video asset individually for secure and trackable playback.
- Signed token authentication: Grants access only if a valid, cryptographically signed token is present in the playback URL.
- Time-limited access: Tokens can include expiration timestamps to allow playback only within a defined time window.
- User-specific control: Tokens can be generated per user or session, restricting access based on identity or device.
- Prevents unauthorized sharing: Signed tokens stop others from reusing the URL, protecting content from piracy and hotlinking.
- Customizable restrictions: Tokens can include rules like IP restrictions, usage limits, or geo-blocking for enhanced security.
DRM (Widevine) Playback
FastPix supports Widevine DRM for protected streams. To enable DRM playback, you must provide both a playbackToken and a drmConfig in the same setFastPixMediaItem call. If playbackToken is set without drmConfig, the player emits a DRM configuration error through PlaybackListener.onError.
Basic DRM setup
import io.fastpix.media3.core.DrmConfig
import io.fastpix.media3.core.FastPixPlayer
import io.fastpix.media3.core.StreamType
val player = FastPixPlayer.Builder(this)
.setAutoplay(true)
.build()
binding.playerView.player = player
player.setFastPixMediaItem {
playbackId = "your-playback-id"
streamType = StreamType.onDemand // Use StreamType.live for live streams
playbackToken = "your-secure-playback-token"
drmConfig = DrmConfig() // Defaults to Widevine UUID, multiSession=true
}Custom DRM options
To override the default Widevine configuration, pass a DrmConfig with explicit parameters:
import androidx.media3.common.C
import io.fastpix.media3.core.DrmConfig
player.setFastPixMediaItem {
playbackId = "your-playback-id"
playbackToken = "your-secure-playback-token"
drmConfig = DrmConfig(
uuid = C.WIDEVINE_UUID,
multiSession = true
)
}Key points:
streamTypedetermines which FastPix DRM license endpoint is used —onDemandorlive.- DRM playback is only supported on physical Android devices. Test on the minimum API level your app targets.
DrmConfig()with no arguments defaults to Widevine UUID withmultiSession = true.
Playback resolution control
private fun startPlayback() {
player?.setFastPixMediaItem {
playbackId = "YOUR_PLAYBACK_ID" // mandatory
minResolution = PlaybackResolution.LD_480
maxResolution = PlaybackResolution.FHD_1080
// Or force a fixed value:
// resolution = PlaybackResolution.HD_720
}
}Benefits:
- Min/max resolution: Set quality boundaries to manage bandwidth and device performance.
- Fixed resolution: Force playback at a specific resolution (for example, always 720p).
- Adaptive range: Let the player switch between defined min–max levels (for example, 480p to 1080p) based on network.
- Optimized playback: Achieve smoother streaming by balancing quality and performance.
- Full control: Tailor video quality to user settings or app-specific requirements.
Rendition order (quality preference)
Define which resolutions should be preferred during adaptive playback (for example, prefer HD over SD when available). You can align playback quality with user-selected settings (like "Data Saver," "Auto," or "High Quality"). The player intelligently switches resolutions based on real-time network and device conditions, while respecting the set priorities. This also helps avoid sudden quality drops or unnecessary resolution changes, maintaining smoother playback.
private fun startPlayback() {
player?.setFastPixMediaItem {
playbackId = "YOUR_PLAYBACK_ID" // mandatory
renditionOrder = RenditionOrder.Descending
}
}Modes:
- Ascending: 144p → 360p → 720p → 1080p (quick startup)
- Descending: 1080p → 720p → 360p → 144p (best-quality first)
Video Quality Switching
These APIs let users select a fixed quality level (for example, 1080p) or return to adaptive bitrate (ABR) mode. They are available on FastPixPlayer and do not reset playback position or recreate the player.
Get available qualities and the current quality
val player = binding.playerView.player as? FastPixPlayer ?: return
// All available quality tracks for the current media
val qualities: List<VideoTrack> = player.getVideoQualities()
// Currently active quality (in ABR mode, reflects the rendition currently rendering)
val current: VideoTrack? = player.getCurrentVideoQuality()Each VideoTrack exposes: id, width, height, bitrate, label, isSelected, and isAuto.
Switch to a fixed quality
// Pass a track id from getVideoQualities()
player.setVideoQuality(trackId)Switch back to ABR (auto)
player.enableAutoQuality()Always include an Auto option in your quality menu that calls enableAutoQuality(). This lets the player resume adaptive switching after the user has selected a fixed rendition.
Listen for quality changes
player.addPlaybackListener(object : PlaybackListener {
override fun onVideoQualityChanged(
quality: VideoTrack?,
source: PlaybackListener.VideoQualityChangeSource
) {
// source = MANUAL → triggered by setVideoQuality() or enableAutoQuality()
// source = ABR → triggered automatically by the SDK
updateQualityUi(quality, source)
}
override fun onPlay() {}
override fun onPause() {}
override fun onPlaybackStateChanged(isPlaying: Boolean) {}
override fun onError(error: PlaybackException) {}
})Key points:
- Quality changes are applied after any in-progress seek completes.
- Use
sourceinonVideoQualityChangedto distinguish between user-initiated and SDK-initiated rendition switches.
Custom domain support
private fun startPlayback() {
player?.setFastPixMediaItem {
playbackId = "YOUR_PLAYBACK_ID" // mandatory
customDomain = "stream.yoursite.com" // optional (defaults to stream.fastpix.io)
}
}Why use a custom domain:
- Stream videos directly from your own domain (for example,
stream.yoursite.com) instead of default CDN URLs. - Supports public and private content.
- You can use signed playback tokens for private videos to restrict access to authorized users only.
- Manage who can view your content with minimal setup using domain and token-based security.
- Hosting via your custom domain can improve performance and ensure better branding consistency.
- Seamless transition for white-labeled apps.
Full configuration example
The complete example below includes listener setup, URL generation, player configuration, seek preview, and analytics:
import io.fastpix.media3.PlayerView
import io.fastpix.media3.PlaybackListener
import io.fastpix.media3.analytics.AnalyticsConfig
import io.fastpix.media3.core.FastPixPlayer
import io.fastpix.media3.core.PlaybackResolution
import io.fastpix.media3.core.RenditionOrder
import io.fastpix.media3.seekpreview.models.PreviewFallbackMode
import io.fastpix.media3.seekpreview.models.SeekPreviewConfig
import io.fastpix.data.domain.model.VideoDataDetails
import androidx.media3.common.PlaybackException
class CustomizedPlayerActivity : AppCompatActivity() {
private lateinit var binding: ActivityCustomizedPlayerBinding
private val playerView get() = binding.playerView
private var player: FastPixPlayer? = null
private lateinit var playbackListener: PlaybackListener
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityCustomizedPlayerBinding.inflate(layoutInflater)
setContentView(binding.root)
val seekPreviewConfig = SeekPreviewConfig.Builder()
.setEnabled(true)
.setFallbackMode(PreviewFallbackMode.TIMESTAMP)
.setEnablePreload(true)
.setPreloadRadius(1)
.setCacheEnabled(true)
.build()
val analyticsConfig = AnalyticsConfig.Builder(playerView, "YOUR_WORKSPACE_ID")
.setVideoDataDetails(VideoDataDetails(videoId = "videoId", videoTitle = "videoTitle"))
.setEnabled(true)
.build()
player = FastPixPlayer.Builder(this)
.setAutoplay(true)
.setLoop(false)
.setSeekPreviewConfig(seekPreviewConfig)
.setAnalyticsConfig(analyticsConfig)
.build()
playerView.player = player
}
override fun onStart() {
super.onStart()
startPlayback()
}
private fun startPlayback() {
playbackListener = object : PlaybackListener {
override fun onPlay() {}
override fun onPause() {}
override fun onPlaybackStateChanged(isPlaying: Boolean) {}
override fun onError(error: PlaybackException) {}
}
player?.addPlaybackListener(playbackListener)
val ok = player?.setFastPixMediaItem {
playbackId = "YOUR_PLAYBACK_ID"
minResolution = PlaybackResolution.LD_480
maxResolution = PlaybackResolution.FHD_1080
renditionOrder = RenditionOrder.Descending
playbackToken = "SET_PLAYBACK_TOKEN"
customDomain = "SET_CUSTOM_DOMAIN"
} ?: false
if (!ok) return
}
override fun onStop() { super.onStop() }
override fun onPause() { super.onPause() }
override fun onDestroy() {
super.onDestroy()
player?.removePlaybackListener(playbackListener)
if (isFinishing) {
playerView.release()
}
}
}SDK API reference
This section documents the SDK's primary API surface and how to use it.
Player objects
io.fastpix.media3.PlayerView: UI component for XML layouts. It renders video and owns aFastPixPlayerinstance.io.fastpix.media3.core.FastPixPlayer: The core player (wrapping Media3 ExoPlayer). This is where most controls and callbacks live.
Typical pattern:
val player = FastPixPlayer.Builder(context)
.setAutoplay(true)
.setLoop(false)
.build()
playerView.player = playerMedia setup (FastPix streams vs. direct URL)
FastPix playback (Recommended)
Use this when you have a playbackId from the FastPix dashboard.
val ok = player.setFastPixMediaItem {
playbackId = "YOUR_PLAYBACK_ID" // required
// Optional playback security:
playbackToken = "YOUR_PLAYBACK_TOKEN"
// Optional custom domain:
customDomain = "stream.yoursite.com" // default: stream.fastpix.io
// Optional quality controls:
minResolution = PlaybackResolution.LD_480
maxResolution = PlaybackResolution.FHD_1080
// resolution = PlaybackResolution.HD_720 // fixed quality
renditionOrder = RenditionOrder.Descending
// StreamType is currently reserved for future use:
// streamType = StreamType.onDemand
}
if (!ok) {
// Validation failed (for example, empty playbackId). Details arrive via PlaybackListener.onError().
}Direct URL playback
Use this when you already have a URL (HLS .m3u8, DASH, progressive MP4, etc.).
player.setMediaItem(MediaItem.fromUri("https://example.com/video.m3u8"))Playback controls (Play / Pause / Seek / State)
These methods are on FastPixPlayer and are safe to call from the main thread (recommended). They delegate to Media3 internally.
player.play() // start/resume
player.pause() // pause
player.togglePlayPause() // toggle
player.seekTo(positionMs = 5_000) // seek to 5s
val isAutoPlay = player.autoplay // whether playWhenReady is set when ready
player.setPlayWhenReady(true) // start automatically when ready
val willPlayWhenReady = player.getPlayWhenReady()
val pos = player.getCurrentPosition()
val duration = player.getDuration()
val state = player.getPlaybackState() // Media3: STATE_IDLE/BUFFERING/READY/ENDEDBehavior details:
play(): Starts playback if prepared; if buffering/ready, it resumes. CallsetMediaItem(...)orsetFastPixMediaItem { ... }first.pause(): Pauses if playing.togglePlayPause(): Convenience for tap gestures or a single button.seekTo(ms): Seeks within the current item. Seek events are surfaced viaPlaybackListener.onSeekStartandonSeekEnd.getDuration(): Returns0Lwhen unknown.getPlaybackState(): Media3 playback state. Use with buffering callbacks to show spinners.setPlayWhenReady(true)/autoplay: Use either, depending on whether you want a one-off "start when ready" vs a persistent player-level policy.
Volume and mute / unmute
player.setVolume(0.75f) // 0.0..1.0
val vol = player.getVolume()
player.mute()
player.unmute()Behavior details:
setVolume(x): Clamps to0.0 ≤ x ≤ 1.0.mute()/unmute():mute()stores the previous non-zero volume andunmute()restores it (or defaults to 1.0 if nothing was saved).- Device volume buttons: The SDK monitors system volume while you have at least one playback listener attached and fires
PlaybackListener.onVolumeChanged(volumeLevel)andPlaybackListener.onMuteStateChanged(isMuted).
Playback speed (rate control)
The SDK supports speeds from 0.25x to 2.0x.
player.setPlaybackSpeed(1.5f) // picks closest supported speed if needed
val speed = player.getPlaybackSpeed()
val all = player.getAvailablePlaybackSpeeds() // FloatArray
player.fast() // next speed (wraps)
player.slow() // previous speed (wraps)
player.normalize() // back to 1.0xListen for speed changes with PlaybackListener.onPlaybackRateChanged(rate).
Playback callbacks (PlaybackListener)
PlaybackListener)Attach a listener to receive events. All callbacks are invoked on the main thread.
val listener = object : PlaybackListener {
override fun onPlay() {
// Playback started/resumed
}
override fun onPause() {
// Playback paused (not called for ended/idle transitions)
}
override fun onPlaybackStateChanged(isPlaying: Boolean) {
// Unified play/pause state changes
}
override fun onPlayerReady(durationMs: Long) {
// Called once per media item when player becomes READY the first time
}
override fun onTimeUpdate(currentPositionMs: Long, durationMs: Long, bufferedPositionMs: Long) {
// Periodic time updates during active playback (default ~500ms)
}
override fun onSeekStart(currentPositionMs: Long) {
// Fired when a seek begins (user scrub or programmatic seekTo)
}
override fun onSeekEnd(fromPositionMs: Long, toPositionMs: Long, durationMs: Long) {
// Fired when seek completes (READY again or discontinuity completes)
}
override fun onBufferingStart() {
// Transition to buffering
}
override fun onBufferingEnd() {
// Transition from buffering to ready
}
override fun onVolumeChanged(volumeLevel: Float) {
// Device volume changed (0.0..1.0)
}
override fun onMuteStateChanged(isMuted: Boolean) {
// Convenience mute state
}
override fun onPlaybackRateChanged(rate: Float) {
// Playback speed updated
}
override fun onCompleted() {
// Reached end of media (still called even if loop=true, before repeating)
}
override fun onError(error: PlaybackException) {
// Playback or validation error
}
}
player.addPlaybackListener(listener)Callback semantics (practical notes):
onPlayerReady(durationMs): Fires once per media item when the player reaches READY the first time (not on every rebuffer/seek).onTimeUpdate(...): Fires periodically during active playback (default ~500ms) and stops automatically when paused/ended or when no listeners remain.onSeekStart/onSeekEnd: Triggered for both user scrubs and programmaticseekTocalls.onBufferingStart/onBufferingEnd: Emitted on buffering transitions; ideal for showing/hiding a spinner.onCompleted(): Called when reaching the end; ifloop = true, still fired before the video repeats.
Remove the listener when you're done:
player.removePlaybackListener(listener)Analytics (FastPix Data Core SDK)
The FastPix Android Data Core SDK provides analytics for FastPix playback on Android. It is not a standalone video player. Instead, it integrates with your player and automatically captures playback analytics, including:
- Playback lifecycle events (play, pause, ready, complete, errors)
- Buffering behavior and seek patterns
- Engagement signals and session-level playback usage
The SDK sends collected analytics to your FastPix workspace, where you can monitor them in near real time through the FastPix dashboard. The integration is lightweight and does not interrupt or degrade playback.
What it is for
Use analytics when you want to:
- Measure viewer engagement and completion trends
- Detect buffering and quality-of-experience issues
- Correlate playback behavior with video metadata (for example, title and ID,etc)
- Monitor player health and failures in production
How to use it
Configure analytics using AnalyticsConfig and pass it to FastPixPlayer.Builder.
import io.fastpix.data.domain.model.VideoDataDetails
import io.fastpix.media3.analytics.AnalyticsConfig
import io.fastpix.media3.core.FastPixPlayer
val videoDataDetails = VideoDataDetails("video-123", "Launch Demo")
val analyticsConfig = AnalyticsConfig.Builder(
playerView = binding.playerView, // Required
workSpaceId = "your-workspace-id" // Required
)
.setVideoDataDetails(videoDataDetails) // Optional metadata
.setEnabled(true) // default is true
.build()
val fastPixPlayer = FastPixPlayer.Builder(this)
.setAutoplay(true)
.setLoop(false)
.setAnalyticsConfig(analyticsConfig)
.build()
binding.playerView.player = fastPixPlayerNotes
playerViewandworkSpaceIdare mandatory.videoDataDetails,playerDataDetails, andcustomDataDetailsare optional and can be added based on your use case.- If analytics setup fails at runtime, playback continues. Analytics is fail-safe by design.
- Current analytics APIs are optimized for Java-first Android integration. Kotlin ergonomics and customization options will improve in future releases.
Seek preview (spritesheet thumbnails)
Seek preview shows thumbnail previews while the user scrubs. When enabled (via FastPixPlayer.Builder.setSeekPreviewConfig(...)), you can wire seek preview into your scrubbing UI:
- Call
sdk.showPreview()when the user starts dragging. - Call
sdk.loadPreview(positionMs)while dragging (safe to call frequently). - Call
sdk.hidePreview()when the user stops dragging.
How spritesheets are resolved (FastPix streams)
- Stream URL:
https://stream.fastpix.io/{playbackId}.m3u8 - Spritesheet metadata:
https://images.fastpix.io/{playbackId}/spritesheet.json
If the spritesheet does not exist, or the current media is not a FastPix stream, the SDK follows PreviewFallbackMode:
TIMESTAMP: Shows a time label (for example"02:30");SpritesheetMetadata.bitmapmay be null.NONE: Shows nothing.
Enable seek preview during player creation
val seekPreviewConfig = SeekPreviewConfig.Builder()
.setEnabled(true)
.setFallbackMode(PreviewFallbackMode.TIMESTAMP) // or NONE
.setEnablePreload(true)
.setPreloadRadius(1)
.setCacheEnabled(true)
.build()
val player = FastPixPlayer.Builder(context)
.setSeekPreviewConfig(seekPreviewConfig)
.build()Listen for preview lifecycle and frames
player.setSeekPreviewListener(object : SeekPreviewListenerAdapter() {
override fun onSpritesheetInitialized() {
// Spritesheet metadata is available and preview can be used
}
override fun onSpritesheetFailed(error: Throwable) {
// Spritesheet unavailable; fallback may still work depending on config
}
override fun onPreviewShow() {
// Show your preview container
}
override fun onPreviewHide() {
// Hide your preview container
}
override fun onSpritesheetLoaded(metadata: SpritesheetMetadata) {
// metadata.bitmap: bitmap for current position (can be null in timestamp fallback)
// metadata.timestampMs: current seek timestamp (ms)
// Additional fields: rows/columns/frameWidth/frameHeight/frameCount
// durationMs/intervalMs (distance between frames)
}
})Hook to SeekBar scrubbing
seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onStartTrackingTouch(seekBar: SeekBar) {
player.showPreview()
}
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
player.loadPreview(progress.toLong()) // recommended: progress in ms
}
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
player.hidePreview()
player.seekTo(seekBar.progress.toLong())
}
})Optional: Request a preview bitmap directly
If you want to render previews yourself (for example, custom UI), you can fetch bitmaps:
// Call from a coroutine
val bmp = player.getPreviewBitmap(timeMs = 30_000)
val label = player.formatTimestamp(timeMs = 30_000)Audio tracks (discovery and switching)
FastPixPlayer can discover and switch audio tracks (commonly on HLS streams with multiple audio renditions).
What an AudioTrack contains (useful for UI):
id: Pass this tosetAudioTrack(id).languageCode/languageName/label: Show in your menu.isSelected,isPlayable,isDefault: For UI state.- Optional diagnostics:
role,channels,codec,bitrate,groupId.
Listen for audio track updates
import io.fastpix.media3.tracks.AudioTrackListener
import io.fastpix.media3.tracks.AudioTrackUpdateReason
player.addAudioTrackListener(object : AudioTrackListener {
override fun onAudioTracksLoaded(tracks: List<AudioTrack>, reason: AudioTrackUpdateReason) {
// Populate your UI (language menu, etc.)
// Each AudioTrack has an id; use it to switch.
}
override fun onAudioTracksChange(selectedTrack: AudioTrack) {
// Update selected UI state
}
override fun onAudioTrackSwitching(isSwitching: Boolean) {
// Optional: show/hide a "switching" indicator
}
override fun onAudioTracksLoadedFailed(error: AudioTrackError) {
// Handle invalid id, player not ready, selection failure, etc.
}
})Switch audio track by ID
NOTE:
If a seek is in progress, the SDK defers switching until the seek completes.
val tracks = player.getAudioTracks()
val target = tracks.firstOrNull() ?: return
player.setAudioTrack(target.id)Example: Build a simple language menu
val tracks = player.getAudioTracks()
val items = tracks.filter { it.isPlayable }.map { t ->
val title = t.languageName ?: t.label ?: t.languageCode ?: "Unknown"
title to t.id
}
// Present items in a dialog; on click: player.setAudioTrack(id)Subtitles (Discovery, Switching, and Cues)
What a SubtitleTrack contains:
id: Pass tosetSubtitleTrack(id).languageCode/languageName/labelisSelected,isPlayable,isDefault,isForced- Optional:
role,codec,groupId
Listen for subtitle track updates and cue changes
import io.fastpix.media3.tracks.SubtitleTrackListener
player.addSubtitleTrackListener(object : SubtitleTrackListener {
override fun onSubtitlesLoaded(tracks: List<SubtitleTrack>) {
// Populate subtitle selection UI
}
override fun onSubtitleChange(track: SubtitleTrack?) {
// track == null means subtitles disabled
}
override fun onSubtitlesLoadedFailed(error: SubtitleTrackError) {
// Track not found, not playable, player not ready, etc.
}
override fun onSubtitleCueChange(info: SubtitleRenderInfo) {
// Optional: observe cues (text + timing) if building a custom subtitle renderer
}
})Switch subtitle track by ID, or disable subtitles
val subs = player.getSubtitleTracks()
val target = subs.firstOrNull()
if (target != null) {
player.setSubtitleTrack(target.id)
} else {
player.disableSubtitles()
}Preferred / Default language (auto selection)
These preferences apply automatically when tracks become available, and never override a manual selection:
player.setDefaultAudioTrack(languageName = "English")
player.setDefaultSubtitleTrack(languageName = "Spanish")NOTE:
Use BCP-47 / ISO language names like"English","Spanish","Hindi","French". If the preferred language does not exist in the stream, the player keeps its normal selection.
PlayerView details (XML integration tips)
If you are using the XML io.fastpix.media3.PlayerView, the following properties are important:
- Configuration-change survival: By default
PlayerView.retainPlayerOnConfigChange = true. For best results, assign anandroid:idin XML; otherwise the view cannot retain/recover the stored player instance across rotation. - Tap gesture:
playerView.isTapGestureEnabled = trueenables single-tap toggle play/pause usingtogglePlayPause(). - Release: Call
playerView.release()when the Activity is finishing (onDestroywithisFinishing == true) to force a real release even if retention is enabled.
Changelog
All notable changes to the FastPix Player for Android is documented below.
Current verison
[1.0.9]
Added
-
DRM Support (Widevine): SDK-level DRM abstraction for protected content playback
- Added
DrmConfigdata class for configuring DRM without exposing Media3 internals - Added
DrmManagerinternal manager that builds Media3DrmConfigurationfrom SDK config - Added
drmConfigproperty inFastPixMediaItemBuilderto enable DRM on a per-media-item basis - DRM license URL is auto-constructed from
playbackId,playbackToken, andstreamType— no manual URL assembly required - Widevine UUID and multi-session enabled by default
- Added
-
Video Quality Switching: Manual and automatic video quality (rendition) selection
- Added
VideoTrackdata model exposingid,width,height,bitrate,label,isSelected, andisAuto - Added
getVideoQualities()to retrieve available video renditions sorted by resolution - Added
getCurrentVideoQuality()to get the currently active rendition - Added
setVideoQuality(trackId: String)to lock playback to a specific quality - Added
enableAutoQuality()to re-enable adaptive bitrate (ABR) selection - Quality switches are deferred during seek operations and applied on seek completion
- Video track discovery integrated into
TrackManageralongside existing audio/subtitle track management
- Added
Previous version
[1.0.8]
- Bumped
media3-dataversion from1.2.4to1.2.5
[1.0.7]
Updates:
- Bumped
media3version from1.2.3to1.2.4 - Updated library version to
1.0.7inREADME.md,build.gradle.kts, andFastPixPlayerLibraryInfo.kt - Added
AnalyticsConfigandVideoDataDetailsintegration inMainActivity - Refactored and cleaned up code in
MainActivity.kt
[1.0.6] - 2026
Fix
- Crash Fix on Seek Preview Config
[1.0.5] - 2026
Added
-
Audio Track Switching: Support for discovering and switching between multiple audio tracks
- Added
getAudioTracks()to retrieve available audio tracks - Added
getCurrentAudioTrack()to get the currently selected track - Added
setAudioTrack(trackId: String)to switch audio tracks dynamically without interrupting playback - Added
setDefaultAudioTrack(languageCode: String)to automatically select preferred language - Added
AudioTrackListenerwith callbacks:onAudioTracksLoaded()onAudioTracksChange()onAudioTracksLoadedFailed()onAudioTrackSwitching()
- Added
-
Subtitle Track Switching: Support for subtitles with dynamic switching and rendering
- Added
getSubtitleTracks()to retrieve available subtitle tracks - Added
getCurrentSubtitleTrack()to get current subtitle selection - Added
setSubtitleTrack(trackId: String)to enable specific subtitle track - Added
disableSubtitles()to turn off subtitles - Added
setDefaultSubtitleTrack(languageCode: String)for automatic subtitle selection - Added
SubtitleTrackListenerwith callbacks:onSubtitlesLoaded()onSubtitleChange()onSubtitlesLoadedFailed()onSubtitleCueChange()
- Added
-
Subtitle Rendering Support
- Introduced
SubtitleCueInfoandSubtitleRenderInfofor real-time subtitle rendering - Enables custom subtitle UI implementation using cue updates
- Introduced
[1.0.4] - 2026
Added
- Seek Preview (Spritesheet thumbnails): Thumbnail previews while scrubbing
- Added
SeekPreviewConfigto configure seek preview behavior (enabled, preload, cache, fallback mode) - Added
PreviewFallbackModefor graceful fallback when thumbnails are unavailable (timestamp/none) - Added
SeekPreviewListenercallbacks:onSpritesheetInitialized,onSpritesheetFailed,onPreviewShow,onPreviewHide,onSpritesheetLoaded - Added
FastPixPlayer.Builder.setSeekPreviewConfig(config: SeekPreviewConfig?)to enable seek preview at player creation time - Added
FastPixPlayer.setSeekPreviewListener(listener: SeekPreviewListener?)to receive preview frames - Added
FastPixPlayer.showPreview(),FastPixPlayer.loadPreview(timeMs),FastPixPlayer.hidePreview()for seek-bar integration - Default FastPix spritesheet URL is auto-resolved from the current stream URL (e.g.
stream.fastpix.io→images.fastpix.io+/{playbackId}/spritesheet.json)
- Added
[1.0.3] - 2026
Added
-
Volume Control: Comprehensive volume management API
- Added
setVolume(volume: Float)method to set volume level (0.0f to 1.0f) - Added
getVolume()method to get current volume level - Added
mute()method to mute playback (saves current volume for restoration) - Added
unmute()method to restore previous volume level - Added
onVolumeChanged(volumeLevel: Float)callback inPlaybackListener- triggered when device volume changes via hardware buttons or system controls - Added
onMuteStateChanged(isMuted: Boolean)callback inPlaybackListener- triggered when mute state changes - Automatic device volume monitoring with periodic checks (200ms interval)
- Volume state is preserved across configuration changes
- Added
-
AutoPlay Support: Automatic playback start when media is ready
- Added
setAutoplay(autoplay: Boolean)method inFastPixPlayer.Builderto configure autoplay during player creation - Added
autoplayproperty onFastPixPlayerto enable/disable autoplay at runtime - When enabled, playback automatically starts when media is ready to play
- No manual call to
play()required when autoplay is enabled - Autoplay state is preserved across configuration changes
- Added
-
Loop Playback: Seamless looping functionality
- Added
setLoop(loop: Boolean)method inFastPixPlayer.Builderto configure loop during player creation - Added
loopproperty onFastPixPlayerto enable/disable looping at runtime - When enabled, playback automatically restarts from the beginning when it reaches the end
- Current media item repeats indefinitely until loop is disabled
- Loop state is preserved across configuration changes
- Added
-
Playback Rate Control: Flexible playback speed adjustment
- Added
setPlaybackSpeed(speed: Float)method to set playback speed to a specific value - Added
getPlaybackSpeed()method to get current playback speed - Added
getAvailablePlaybackSpeeds()method to get all available speed options - Available playback speeds: 0.25x, 0.5x, 0.75x, 1.0x, 1.25x, 1.5x, 1.75x, 2.0x
- Added
onPlaybackRateChanged(rate: Float)callback inPlaybackListener- triggered when playback speed changes - Playback speed automatically adjusts to closest available speed if exact value is not available
- Playback speed state is preserved across configuration changes
- Added
[1.0.2] - 2026
Improved
- Code Optimization
- Refactoring
[1.0.1] - 2026
Added
-
Playback Control Methods: Simple and intuitive playback control API
- Added
play()method to start or resume playback - Added
pause()method to pause playback - Added
togglePlayPause()method to toggle between play and pause states - Added
isPlaying()method to check current playback state
- Added
-
PlaybackListener Interface: Comprehensive event-driven architecture for playback monitoring
- Added
onPlay()callback - triggered when playback starts or resumes - Added
onPause()callback - triggered when playback is paused - Added
onPlaybackStateChanged(isPlaying: Boolean)callback - triggered on play/pause state changes - Added
onError(error: PlaybackException)callback - triggered when playback errors occur - Added
onTimeUpdate(currentPositionMs, durationMs, bufferedPositionMs)callback - continuous time updates during playback (similar to HTML5onTimeUpdate)- Invoked approximately every 500ms during active playback
- Provides current position, total duration, and buffered position
- Enables real-time UI updates for seek bars and time displays
- Added
onSeekStart(currentPositionMs)callback - triggered when seek operations begin - Added
onSeekEnd(fromPositionMs, toPositionMs, durationMs)callback - triggered when seek operations complete - Added
onBufferingStart()callback - triggered when player enters buffering state - Added
onBufferingEnd()callback - triggered when player exits buffering state - All callbacks are invoked on the main thread
- Optional callbacks have default empty implementations for flexibility
- Added
-
Listener Management: Methods for managing playback listeners
- Added
addPlaybackListener(listener: PlaybackListener)method - Added
removePlaybackListener(listener: PlaybackListener)method - Added
clearPlaybackListeners()method
- Added
Improved
- Enhanced player API with more intuitive playback control methods
- Better developer experience for building custom playback UIs with comprehensive callbacks
- Real-time time updates enable smooth seek bar and time display synchronization
- Seek operation tracking provides better UX during seeking
Technical Details
- Playback speed is implemented using Media3's
PlaybackParametersAPI - Speed state is preserved across configuration changes
- All speed methods are available on both
PlayerViewand the underlying player instance - Time updates are automatically managed - start when playback begins, stop when paused/ended
- Seek callbacks automatically pause time updates during seek operations for better performance
[1.0.0]
Initial Release:
The first public release of the FastPix Android Player SDK, packed with modern playback capabilities for both live and on-demand streaming scenarios.
-
Support for Public & Private Media: Secure token-based playback for private videos and effortless access for public streams.
-
Live & On-Demand Streaming: Adaptive support for both real-time and pre-recorded content with optimized buffering strategies.
-
Audio Track Switching: Dynamically switch between available audio tracks, ensuring accessibility and multi-language support.
-
Subtitle Track Switching: Enhance viewer experience with support for multiple subtitle tracks and on-the-fly switching.
-
QoE & Playback Metrics: Built-in tracking of key Video Quality of Experience (QoE) indicators such as: rebuffer events, bitrate/resolution changes, and startup time — enabling deep insights into playback performance.
-
Custom Playback Resolution: Programmatically set or limit playback resolution to suit user preferences or bandwidth constraints.
-
Stream Type Configuration: Fine-tuned handling of stream types like HLS, DASH, and others — with control over live latency modes and playback strategies.
-
Custom Domain Support: Compatible with FastPix's custom domain system for secure and branded media delivery.
-
Rendition Order Control: Configure and prioritize video renditions based on bitrate, resolution, etc., to ensure predictable quality behavior. Supports both ascending (low ➜ high) and descending (high ➜ low) strategies. Ideal for optimizing playback under bandwidth constraints or enforcing quality-first strategies.
Updated 19 days ago