Deleting exoplayer from project

updating to media player 3 in MoreHomeActivity SongAdapter and Player on HomeFragment 1 and 2

Error handing in PlayerActivity.kt and LiveStreamPlayerActivity.kt
This commit is contained in:
2024-07-02 20:56:17 +05:30
parent 234a274a72
commit 69a8c34a57
15 changed files with 340 additions and 105 deletions

View File

@@ -49,7 +49,7 @@ android {
}
ext.jwPlayerVersion = '4.17.0'
ext.exoplayerVersion = '1.1.1'
ext.exoplayerVersion = '1.3.1'
dependencies {
implementation "com.facebook.shimmer:shimmer:0.5.0"
@@ -84,10 +84,29 @@ dependencies {
implementation "com.jwplayer:jwplayer-core:$jwPlayerVersion"
implementation "com.jwplayer:jwplayer-common:$jwPlayerVersion"
// exoplayer2
implementation 'com.google.android.exoplayer:exoplayer-core:2.19.1'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.19.1'
implementation 'com.google.android.exoplayer:exoplayer-hls:2.19.1'
// media player 3
def media3_version = "1.3.1"
implementation "androidx.media3:media3-exoplayer:$media3_version"
// For DASH playback support with ExoPlayer
implementation "androidx.media3:media3-exoplayer-dash:$media3_version"
// For HLS playback support with ExoPlayer
implementation "androidx.media3:media3-exoplayer-hls:$media3_version"
// For SmoothStreaming playback support with ExoPlayer
implementation "androidx.media3:media3-exoplayer-smoothstreaming:$media3_version"
// Common functionality for reading and writing media containers
implementation "androidx.media3:media3-container:$media3_version"
// Common functionality for media database components
implementation "androidx.media3:media3-database:$media3_version"
// Common functionality for media decoders
implementation "androidx.media3:media3-decoder:$media3_version"
// Common functionality for loading data
implementation "androidx.media3:media3-datasource:$media3_version"
// Common functionality used across multiple media libraries
implementation "androidx.media3:media3-common:$media3_version"
// For extracting data from media containers
implementation "androidx.media3:media3-extractor:$media3_version"
// For building media playback UIs
implementation "androidx.media3:media3-ui:$media3_version"
implementation libs.androidx.core.ktx
implementation libs.androidx.appcompat

View File

@@ -16,6 +16,7 @@ import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.media3.common.Player.Listener
import com.woka.R
import com.woka.WokaApp.Companion.userPrefs
import com.woka.audiobooks.views.AudioBooksActivity
@@ -34,7 +35,7 @@ import com.woka.utils.show
import com.woka.webseries.views.WebSeriesActivity
class Home1Fragment : Fragment() {
class Home1Fragment : Fragment(), Listener {
private lateinit var binding: FragmentHome1Binding
private lateinit var viewModel: HomeViewModel
@@ -108,6 +109,7 @@ class Home1Fragment : Fragment() {
private fun initPlayerView() {
binding.playerView.player = viewModel.player
binding.playerView.useController = false
viewModel.player?.addListener(this)
}
private fun setObservers() {
@@ -190,6 +192,7 @@ class Home1Fragment : Fragment() {
override fun onDestroyView() {
super.onDestroyView()
activity?.unregisterReceiver(minuteReceiver)
viewModel.player?.removeListener(this)
}
private fun updateUserData(data: UserDataResponse?) {

View File

@@ -2,18 +2,23 @@ package com.woka.home.viewmodels
import android.content.Context
import android.net.Uri
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.MediaItem
import androidx.media3.common.MediaItem
import androidx.media3.common.PlaybackException
import androidx.media3.common.Player
import androidx.media3.common.Player.Listener
import androidx.media3.exoplayer.ExoPlayer
import com.woka.home.views.BottomNavigation.Companion.HOME
import com.woka.networking.ApiResult
import com.woka.userdata.UserRepository
import com.woka.utils.TAG
import kotlinx.coroutines.launch
class HomeViewModel: ViewModel(){
class HomeViewModel : ViewModel() {
var selectedBottomTab: Int = HOME
var isHomeBackgroundBlurred: Boolean = false
@@ -30,32 +35,30 @@ class HomeViewModel: ViewModel(){
val deActivateLiveData: LiveData<ApiResult<Any>?>
get() = _deActivateLiveData
var player: ExoPlayer? = null
var player: Player? = null
fun initPlayer(context: Context) {
player = ExoPlayer.Builder(context).build()
player?.volume = 0f
val videoUri = Uri.parse("https://d3volyx7jx7oal.cloudfront.net/master.m3u8")
val mediaItem = MediaItem.fromUri(videoUri)
player?.setMediaItem(mediaItem)
player?.setMediaItem(MediaItem.fromUri("https://d3volyx7jx7oal.cloudfront.net/master.m3u8"))
player?.playWhenReady = true
player?.prepare()
}
fun sendLocaleChangeEvent(locale: String){
fun sendLocaleChangeEvent(locale: String) {
_localeChangeLiveData.postValue(locale)
}
fun logout(){
fun logout() {
viewModelScope.launch {
_logoutLiveData.postValue(ApiResult.Loading())
_logoutLiveData.postValue(UserRepository.logout())
}
}
fun deActivateAccount(){
fun deActivateAccount() {
viewModelScope.launch {
_deActivateLiveData.postValue(ApiResult.Loading())
_deActivateLiveData.postValue(UserRepository.deActivateAccount())

View File

@@ -1,7 +0,0 @@
package com.woka.home.viewmodels
import androidx.lifecycle.ViewModel
class MoreViewModel: ViewModel() {
}

View File

@@ -11,16 +11,14 @@ import android.view.WindowManager
import androidx.activity.enableEdgeToEdge
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.ViewModelProvider
import androidx.media3.common.MediaItem
import androidx.recyclerview.widget.SimpleItemAnimator
import com.bumptech.glide.Glide
import com.google.android.exoplayer2.MediaItem
import com.woka.R
import com.woka.WokaApp
import com.woka.WokaApp.Companion.userPrefs
import com.woka.databinding.ActivityMoreHomeBinding
import com.woka.databinding.DialogBlogsBinding
import com.woka.home.viewmodels.MoreViewModel
import com.woka.modules.blogs.BlogsAdapter
import com.woka.modules.blogs.BlogsRepository
import com.woka.modules.blogs.models.Blog
@@ -39,8 +37,6 @@ class MoreHomeActivity : WokaBaseActivity() {
private lateinit var blogsAdapter: BlogsAdapter
private lateinit var viewModel: MoreViewModel
private lateinit var songsAdapter: WokaSongsAdapter
private lateinit var blogBinding: DialogBlogsBinding
@@ -67,8 +63,6 @@ class MoreHomeActivity : WokaBaseActivity() {
lightStatusBar()
}
viewModel = ViewModelProvider(this)[MoreViewModel::class.java]
blogsAdapter = BlogsAdapter(::obBlogClicked)
songsAdapter = WokaSongsAdapter(this)

View File

@@ -3,28 +3,20 @@ package com.woka.modules.wokasongs
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.media3.common.MediaItem
import androidx.media3.common.PlaybackException
import androidx.media3.common.Player
import androidx.media3.exoplayer.ExoPlayer
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.PlaybackException
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.Player.EVENT_IS_LOADING_CHANGED
import com.woka.R
import com.woka.databinding.WokaSongViewHolderBinding
import com.woka.modules.wokasongs.models.SongData
import com.woka.utils.TAG
import com.woka.utils.formatTime
import com.woka.utils.hide
import com.woka.utils.show
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.math.log
class WokaSongsAdapter(context: Context): RecyclerView.Adapter<WokaSongsAdapter.SongViewHolder>() {

View File

@@ -0,0 +1,5 @@
package com.woka.players.models
enum class PlayBackState{
PLAY, PAUSED, STOPPED;
}

View File

@@ -1,6 +1,12 @@
package com.woka.players.views
import android.net.ConnectivityManager
import android.net.ConnectivityManager.NetworkCallback
import android.net.Network
import android.net.NetworkRequest
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.ViewGroup
import androidx.activity.enableEdgeToEdge
@@ -9,6 +15,7 @@ import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import com.jwplayer.pub.api.JWPlayer
import com.jwplayer.pub.api.PlayReason
import com.jwplayer.pub.api.configuration.PlayerConfig
import com.jwplayer.pub.api.events.EventType
import com.jwplayer.pub.api.events.listeners.VideoPlayerEvents
@@ -16,17 +23,23 @@ import com.jwplayer.pub.api.fullscreen.FullscreenHandler
import com.jwplayer.pub.api.media.playlists.PlaylistItem
import com.woka.databinding.ActivityLiveStreamPlayerBinding
import com.woka.players.KeepScreenOnHandler
import com.woka.players.models.PlayBackState
import com.woka.utils.TAG
import com.woka.utils.hide
import com.woka.utils.show
class LiveStreamPlayerActivity : AppCompatActivity(), FullscreenHandler {
companion object{
private const val TAG = "LiveStreamPlayerActivity_tag"
}
private lateinit var binding: ActivityLiveStreamPlayerBinding
private lateinit var player: JWPlayer
private lateinit var playerConfig: PlayerConfig
private lateinit var networkCallback: NetworkCallback
private var playbackState: PlayBackState? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
@@ -42,31 +55,39 @@ class LiveStreamPlayerActivity : AppCompatActivity(), FullscreenHandler {
WindowCompat.getInsetsController(window, window.decorView)
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
networkCallback = object : NetworkCallback(){
override fun onAvailable(network: Network) {
super.onAvailable(network)
runOnUiThread {
if (playbackState == PlayBackState.STOPPED){
binding.playerView.show()
binding.errorView.hide()
configureAndPlay()
}
}
}
}
setUpPlayer()
addListeners()
configureAndPlay()
clickEvents()
}
override fun onDestroy() {
super.onDestroy()
player.stop()
(getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager).unregisterNetworkCallback(
networkCallback
)
}
private fun setUpPlayer() {
player = binding.playerView.player
player.setFullscreenHandler(this)
player.setFullscreen(true, false)
player.addListener(EventType.ERROR, VideoPlayerEvents.OnErrorListener {
Log.d(TAG, "onError: ${it.errorCode}")
Log.d(TAG, "onError: ${it.exception}")
Log.d(TAG, "onError: ${it.message}")
})
player.addListener(EventType.SETUP_ERROR, VideoPlayerEvents.OnSetupErrorListener {
Log.d(TAG, "setUpPlayer: $it")
})
private fun setUpPlayer(){
player = binding.playerView.getPlayer(this)
// to keep up the screen om when video is being played
KeepScreenOnHandler(player, window)
@@ -78,12 +99,52 @@ class LiveStreamPlayerActivity : AppCompatActivity(), FullscreenHandler {
val playlist: MutableList<PlaylistItem> = ArrayList()
playlist.add(playlistItem)
val config =
PlayerConfig.Builder()
playerConfig = PlayerConfig.Builder()
.playlist(playlist)
.autostart(true)
.build()
player.setup(config)
player.play()
}
private fun addListeners(){
player.addListener(EventType.PLAY, VideoPlayerEvents.OnPlayListener {
playbackState = PlayBackState.PLAY
binding.playerView.show()
binding.errorView.hide()
})
player.addListener(EventType.PAUSE, VideoPlayerEvents.OnPauseListener {
playbackState = PlayBackState.PAUSED
})
player.addListener(EventType.ERROR, VideoPlayerEvents.OnErrorListener {
playbackState = PlayBackState.STOPPED
binding.playerView.hide()
binding.errorView.show()
})
(getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager).registerNetworkCallback(
NetworkRequest.Builder()
.build(),
networkCallback
)
}
private fun configureAndPlay() {
player.setFullscreenHandler(this)
player.setFullscreen(true, false)
player.setup(playerConfig)
}
private fun clickEvents(){
binding.apply {
retryBtn.setOnClickListener {
binding.playerView.show()
binding.errorView.hide()
configureAndPlay()
}
closeBtn.setOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
}
}
override fun onFullscreenRequested() {}

View File

@@ -1,5 +1,8 @@
package com.woka.players.views
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkRequest
import android.os.Bundle
import android.view.ViewGroup
import androidx.activity.enableEdgeToEdge
@@ -9,16 +12,15 @@ import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import com.jwplayer.pub.api.JWPlayer
import com.jwplayer.pub.api.configuration.PlayerConfig
import com.jwplayer.pub.api.events.EventType
import com.jwplayer.pub.api.events.listeners.VideoPlayerEvents
import com.jwplayer.pub.api.fullscreen.FullscreenHandler
import com.woka.databinding.ActivityPlayerBinding
import com.woka.networking.RetrofitHelper
import com.woka.players.KeepScreenOnHandler
import com.woka.players.PlayerApiService
import com.woka.players.models.PlayBackState
import com.woka.players.models.VideoPlayList
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlin.math.round
import com.woka.utils.hide
import com.woka.utils.show
class PlayerActivity : AppCompatActivity(), FullscreenHandler {
@@ -29,11 +31,14 @@ class PlayerActivity : AppCompatActivity(), FullscreenHandler {
private lateinit var binding: ActivityPlayerBinding
private lateinit var player: JWPlayer
private lateinit var config: PlayerConfig
private lateinit var networkCallback: ConnectivityManager.NetworkCallback
private var playbackState: PlayBackState? = null
private var videoPlayList: VideoPlayList? = null
private var playingIndex: Int = 0
private var apiService = RetrofitHelper.getRetrofit().create(PlayerApiService::class.java)
private var seekPosition: Double = 0.0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -53,51 +58,102 @@ class PlayerActivity : AppCompatActivity(), FullscreenHandler {
videoPlayList = intent.getParcelableExtra(EXTRA_PLAY_LIST)
playingIndex = intent.getIntExtra(EXTRA_PLAY_INDEX, 0)
player = binding.playerView.getPlayer(this)
networkCallback = object : ConnectivityManager.NetworkCallback(){
override fun onAvailable(network: Network) {
super.onAvailable(network)
runOnUiThread {
if (playbackState == PlayBackState.STOPPED){
binding.playerView.show()
binding.errorView.hide()
configAndPlay()
}
}
}
}
setUpPlayer()
if (!videoPlayList?.playlist.isNullOrEmpty()) {
setUpPlayer()
addListeners()
configAndPlay()
}
clickEvents()
}
override fun onDestroy() {
makeVideoViewApiCall(player.playlistIndex, round(player.position).toLong())
super.onDestroy()
player.stop()
(getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager).unregisterNetworkCallback(
networkCallback
)
}
private fun setUpPlayer() {
if (videoPlayList == null || videoPlayList?.playlist.isNullOrEmpty()) return
private fun clickEvents(){
binding.apply {
retryBtn.setOnClickListener {
binding.playerView.show()
binding.errorView.hide()
configAndPlay()
}
player.setFullscreenHandler(this)
closeBtn.setOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
}
}
player.setFullscreen(true, false)
private fun setUpPlayer(){
player = binding.playerView.getPlayer(this)
// to keep up the screen om when video is being played
KeepScreenOnHandler(player, window)
val config = PlayerConfig.Builder()
config = PlayerConfig.Builder()
.playlist(videoPlayList?.playlist)
.build()
// to keep up the screen om when video is being played
KeepScreenOnHandler(player, window)
}
private fun configAndPlay() {
player.setFullscreenHandler(this)
player.setFullscreen(true, false)
player.setup(config)
player.playlistItem(playingIndex)
}
private fun makeVideoViewApiCall(playingPosition: Int, watchedDurationSeconds: Long){
videoPlayList?.videoViewRequestDataList?.let {
if (playingPosition >= 0 && playingPosition < it.size){
it[playingPosition].let {videoViewData ->
if (watchedDurationSeconds > 0){
videoViewData.total_watched_duration = "$watchedDurationSeconds"
CoroutineScope(Dispatchers.IO).launch {
apiService.userVideoView(videoViewData)
}
}
}
private fun addListeners(){
player.addListener(EventType.PLAY, VideoPlayerEvents.OnPlayListener {
if (seekPosition > 0){
player.seek(seekPosition)
}
}
seekPosition = 0.0
playbackState = PlayBackState.PLAY
binding.playerView.show()
binding.errorView.hide()
})
player.addListener(EventType.PAUSE, VideoPlayerEvents.OnPauseListener {
playbackState = PlayBackState.PAUSED
})
player.addListener(EventType.ERROR, VideoPlayerEvents.OnErrorListener {
if (player.position != 0.0){
seekPosition = player.position
}
playbackState = PlayBackState.STOPPED
binding.playerView.hide()
binding.errorView.show()
})
player.addListener(EventType.PLAYLIST_ITEM, VideoPlayerEvents.OnPlaylistItemListener {
playingIndex = it.index
})
(getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager).registerNetworkCallback(
NetworkRequest.Builder()
.build(),
networkCallback
)
}
override fun onFullscreenRequested() {}

View File

@@ -126,7 +126,9 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:background="@color/color_primary_dark"
>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/trailer_view"

View File

@@ -13,4 +13,52 @@
android:layout_height="match_parent"
tools:context=".LiveStreamPlayerActivity"/>
<RelativeLayout
android:id="@+id/error_view"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/close_btn"
android:layout_width="15dp"
android:layout_height="15dp"
android:contentDescription="@string/image"
android:src="@drawable/ic_close"
android:layout_margin="25dp"
/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_horizontal"
android:layout_centerInParent="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/something_went_wrong"
android:fontFamily="@font/exo_2"
android:textColor="@color/white"
/>
<TextView
android:id="@+id/retry_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/retry_underline"
android:fontFamily="@font/exo_2_bold"
android:textColor="@color/white"
android:padding="5dp"
/>
</LinearLayout>
</RelativeLayout>
</RelativeLayout>

View File

@@ -1,7 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<com.jwplayer.pub.view.JWPlayerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/player_view"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".players.views.PlayerActivity"/>
android:background="@color/black"
tools:context=".players.views.LiveStreamPlayerActivity">
<com.jwplayer.pub.view.JWPlayerView
android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".LiveStreamPlayerActivity"/>
<RelativeLayout
android:id="@+id/error_view"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/close_btn"
android:layout_width="15dp"
android:layout_height="15dp"
android:contentDescription="@string/image"
android:src="@drawable/ic_close"
android:layout_margin="25dp"
/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_horizontal"
android:layout_centerInParent="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/something_went_wrong"
android:fontFamily="@font/exo_2"
android:textColor="@color/white"
/>
<TextView
android:id="@+id/retry_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/retry_underline"
android:fontFamily="@font/exo_2_bold"
android:textColor="@color/white"
android:padding="5dp"
/>
</LinearLayout>
</RelativeLayout>
</RelativeLayout>

View File

@@ -132,7 +132,7 @@
android:translationZ="0dp"
/>
<com.google.android.exoplayer2.ui.PlayerView
<androidx.media3.ui.PlayerView
android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@@ -202,7 +202,7 @@
/>
<com.google.android.exoplayer2.ui.PlayerView
<androidx.media3.ui.PlayerView
android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@@ -167,6 +167,7 @@
<string name="slash" translatable="false">/</string>
<string name="notifications" translatable="false">Notifications</string>
<string name="retry">Retry</string>
<string name="retry_underline"><u>Retry</u></string>
<string name="no_notifications_found" translatable="false">No notifications found</string>
<string name="favorites" translatable="false">Favorites</string>
<string name="web_series_hindi">WEB SERIES (HINDI)</string>