I am using exoplayer for playing video in recyclerview. I retrieve videos from firebase and play it in exoplayer .But the problem I am facing is all the videos play simultaneously in background and get the messed up. Also it consumes lots of data. If onces the video complete playing the it don't get start again. How can I stop them playing in the background. Here is my code
val uri = Uri.parse(contentDTOs[p1].videourl)
val view = viewholder.findViewById<SimpleExoPlayerView>(R.id.detailviewitem_video_contents)
val exoplayer= ExoPlayerFactory.newSimpleInstance(context,trackSelector)
val datasourcefactory = DefaultHttpDataSourceFactory("exoplayer")
val extractorsFactory=DefaultExtractorsFactory()
val media = ExtractorMediaSource(uri,datasourcefactory,extractorsFactory,null,null)
view.player = exoplayer
exoplayer.prepare(media)
exoplayer.playWhenReady = true
val loopingSource = LoopingMediaSource(media)
exoplayer.playWhenReady = true
exoplayer.prepare(loopingSource)
override fun onPause() {
super.onPause()
exoplayer.stop()
}
override fun onStop() {
super.onStop()
exoplayer.stop()
}
Try moving lines that set playWhenReady = true to onResume(). Using .play() instead of playWhenReady = true in onResume() could be safer (less buggy for your use-case), though.
You should release your player. For release exoPlayer:
private void releasePlayer() {
if (player != null) {
player.release();
player = null;
}
}
And call releasePlayer method form life-cycle method like below:
#Override
public void onPause() {
super.onPause();
if (Util.SDK_INT < 24) {
releasePlayer();
}
}
#Override
public void onStop() {
super.onStop();
if (Util.SDK_INT >= 24) {
releasePlayer();
}
}
Related
I am trying to build an Android app (coded in Kotlin) which plays a random sound file and after it's done, plays another random file and so on. With the current version of the code it seems that more than one files are played at the same time, instead of waiting the previous one to finish.
In the commented lines in my code I tried implementing a countdown timer for each playing of a music file. It results in the following: when I start the app oly one file is played and then it stops (possibly crashes)
class MainActivity : AppCompatActivity() {
fun playSound(running:Int) {
var completition=1
while (running==1 && completition==1) {
completition=0
var rnds = Random.nextInt(0..1)
if (rnds==1 ) {
val mMediaPlayer = MediaPlayer.create(this, R.raw.right)
mMediaPlayer!!.isLooping = false
mMediaPlayer!!.start()
mMediaPlayer!!.setOnCompletionListener { completition=1 }
}
if (rnds==0 ) {val mMediaPlayer = MediaPlayer.create(this, R.raw.left)
mMediaPlayer!!.isLooping = false
mMediaPlayer!!.start()
mMediaPlayer!!.setOnCompletionListener { completition=1 }
}
}
}
fun music(){
var i=1
while(i==1) {
i=0
val random=(0..1).random()
if (random==1){
val refMediaPlayer=MediaPlayer.create(this,R.raw.right)
refMediaPlayer!!.isLooping = false
refMediaPlayer!!.start()
//object :CountDownTimer(1000,100) {
//override fun onTick(p0: Long) {
// TODO("Not yet implemented")
// }
//override fun onFinish() {
//i=1
//}
// }.start();
}
if (random==0){
val refMediaPlayer=MediaPlayer.create(this,R.raw.left)
refMediaPlayer!!.isLooping = false
refMediaPlayer!!.start()
// object :CountDownTimer(1000,100) {
//override fun onTick(p0: Long) {
// TODO("Not yet implemented")
// }
// override fun onFinish() {
// i=1
// }
//}.start();
}
}
}
// 4. Destroys the MediaPlayer instance when the app is closed
// override fun onStop() {
// super.onStop()
// if (mMediaPlayer != null) {
// mMediaPlayer!!.release()
// mMediaPlayer = null
// }
//}
override fun onCreate(savedInstanceState: Bundle?) {
val running=1
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
music()
}
}
I had a similar problem in an application I built. I ended up putting all the sound stuff on a separate thread and pausing the thread for the duration of each audio file. So something like:
// off the main thread
val refMediaPlayer=MediaPlayer.create(this,R.raw.right)
refMediaPlayer!!.isLooping = false
refMediaPlayer!!.start()
// put the exact length of your sound file here in milliseconds
// 5000 = 5 seconds
Thread.sleep(5000L)
The sound will keep playing, but the code's execution will be paused for the amount of time you specify.
I'm not sure of the exact syntax for Kotlin because I use Java.
I want to ask, is it possible to display a video from a web player which is usually displayed using an iframe on the website?
my boss told me to make an application like that,
an example of a video using this
https://vanfem.com/v/8qqlyh8lmxgkn5y
is that possible? is it also possible to use that url in exoplayer?
Add gradle dependency in app/build.gradle
dependencies {
implementation project(":exoplayer-codelab-00")
}
Open the build.gradle file of the exoplayer-codelab-00 module.
Add the following lines to the dependencies section and sync the project.
def mediaVersion = "1.0.0-alpha03"
dependencies {
[...]
implementation "androidx.media3:media3-exoplayer:$mediaVersion"
implementation "androidx.media3:media3-ui:$mediaVersion"
implementation "androidx.media3:media3-exoplayer-dash:$mediaVersion"
}
Open the layout resource file activity_player.xml from the exoplayer-codelab-00 module.
<androidx.media3.ui.PlayerView
android:id="#+id/video_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
In PlayerActivity.kt
private var player: ExoPlayer? = null
private fun initializePlayer() {
player = ExoPlayer.Builder(this)
.build()
.also { exoPlayer ->
viewBinding.videoView.player = exoPlayer
val mediaItem = MediaItem.fromUri(Uri.parse("https://vanfem.com/v/8qqlyh8lmxgkn5y"))
exoPlayer.setMediaItem(mediaItem)
exoPlayer.playWhenReady = playWhenReady
exoPlayer.seekTo(currentItem, playbackPosition)
exoPlayer.prepare()
}
}
public override fun onStart() {
super.onStart()
if (Util.SDK_INT > 23) {
initializePlayer()
}
}
public override fun onStop() {
super.onStop()
if (Util.SDK_INT > 23) {
releasePlayer()
}
}
private fun releasePlayer() {
player?.let { exoPlayer ->
playbackPosition = exoPlayer.currentPosition
currentItem = exoPlayer.currentMediaItemIndex
playWhenReady = exoPlayer.playWhenReady
exoPlayer.release()
}
player = null
}
for more details you can study this codelab and github
so, I am developing a online music player app with json data. here i am using recycelr view to show list of song. I have to face problem in controlling the media player to pause start in another activity. so I create a new file Audio.kt in this file i have create companion object with all the media player methods. And Now I can use mediaplayer anywhere using Audio.[methods]
here is the Audio.kt file
class Audio {
companion object {
val mp = MediaPlayer()
#RequiresApi(Build.VERSION_CODES.LOLLIPOP)
fun loadMediaPlayer(url: String?) {
mp.setAudioAttributes(
AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_MEDIA)
.build()
)
mp.setDataSource(url)
mp.prepareAsync()
mp.setOnPreparedListener {
mp.start()
MainActivity.progressBar.visibility = View.GONE
MainActivity.slidingPlayBtn.visibility = View.VISIBLE
MainActivity.slidingPlayBtn.setImageResource(R.drawable.ic_pause)
MainActivity.main_pbar.visibility = View.GONE
MainActivity.mainPlayBtn.visibility = View.VISIBLE
val duration: Long = Audio.mp.duration.toLong()
val time = kotlin.String.format(
"%02d:%02d",
TimeUnit.MILLISECONDS.toMinutes(duration),
TimeUnit.MILLISECONDS.toSeconds(duration) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration))
)
MainActivity.totalDur.text = time
MainActivity.seekBar.max = duration.toInt()
}
}
fun startMediaPlayer() {
mp.start()
}
fun pauseMediaPlayer() {
mp.pause()
}
fun stopMediaPlayer() {
if (mp.isPlaying) {
mp.stop()
mp.reset()
}
}
fun isNotPlaying(): Boolean {
return !mp.isPlaying
}
fun mediaCurrPos(): Long {
return mp.currentPosition.toLong()
}
fun mediaPlayerSeek(progress: Int) {
mp.seekTo(progress)
}
fun nextMediaPlayer() {
mp.setNextMediaPlayer(MediaPlayer())
}
}
}
so Now my Question, is this good approach? or I could have to face problems in future
have you any other idea to do this?
I have implemented the ExoPlayer in my application using the example from the Codelab : https://codelabs.developers.google.com/codelabs/exoplayer-intro/#3, algo with the example from https://medium.com/google-exoplayer/playing-ads-with-exoplayer-and-ima-868dfd767ea, the only difference is that I use AdsMediaSource instead of the deprecated ImaAdsMediaSource.
My Implementation is this:
class HostVideoFullFragment : Fragment(), AdsMediaSource.MediaSourceFactory {
override fun getSupportedTypes() = intArrayOf(C.TYPE_DASH, C.TYPE_HLS, C.TYPE_OTHER)
override fun createMediaSource(uri: Uri?, handler: Handler?, listener: MediaSourceEventListener?): MediaSource {
#C.ContentType val type = Util.inferContentType(uri)
return when (type) {
C.TYPE_DASH -> {
DashMediaSource.Factory(
DefaultDashChunkSource.Factory(mediaDataSourceFactory),
manifestDataSourceFactory)
.createMediaSource(uri, handler, listener)
}
C.TYPE_HLS -> {
HlsMediaSource.Factory(mediaDataSourceFactory)
.createMediaSource(uri, handler, listener)
}
C.TYPE_OTHER -> {
ExtractorMediaSource.Factory(mediaDataSourceFactory)
.createMediaSource(uri, handler, listener)
}
else -> throw IllegalStateException("Unsupported type for createMediaSource: $type")
}
}
private var player: SimpleExoPlayer? = null
private lateinit var playerView: SimpleExoPlayerView
private lateinit var binding: FragmentHostVideoFullBinding
private var playbackPosition: Long = 0
private var currentWindow: Int = 0
private var playWhenReady = true
private var inErrorState: Boolean = false
private lateinit var adsLoader: ImaAdsLoader
private lateinit var manifestDataSourceFactory: DataSource.Factory
private lateinit var mediaDataSourceFactory: DataSource.Factory
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//Initialize the adsLoader
adsLoader = ImaAdsLoader(activity as Context, Uri.parse("https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpost&cmsid=496&vid=short_onecue&correlator="))
manifestDataSourceFactory = DefaultDataSourceFactory(
context, Util.getUserAgent(context, "BUO-APP"))//TODO change the applicationName with the right application name
//
mediaDataSourceFactory = DefaultDataSourceFactory(
context,
Util.getUserAgent(context, "BUO-APP"),//TODO change the applicationName with the right application name
DefaultBandwidthMeter())
}
private fun initializePlayer() {
/*
* Since the player can change from null (when we release resources) to not null we have to check if it's null.
* If it is then reset again
* */
if (player == null) {
//Initialize the Exo Player
player = ExoPlayerFactory.newSimpleInstance(DefaultRenderersFactory(activity as Context),
DefaultTrackSelector())
}
val uri = Uri.parse(videoURl)
val mediaSourceWithAds = buildMediaSourceWithAds(uri)
//Bind the view from the xml to the SimpleExoPlayer instance
playerView.player = player
//Add the listener that listens for errors
player?.addListener(PlayerEventListener())
player?.seekTo(currentWindow, playbackPosition)
player?.prepare(mediaSourceWithAds, true, false)
//In case we could not set the exo player
player?.playWhenReady = playWhenReady
//We got here without an error, therefore set the inErrorState as false
inErrorState = false
//Re update the retry button since, this method could have come from a retry click
updateRetryButton()
}
private inner class PlayerEventListener : Player.DefaultEventListener() {
fun updateResumePosition() {
player?.let {
currentWindow = player!!.currentWindowIndex
playbackPosition = Math.max(0, player!!.contentPosition)
}
}
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
//The player state has ended
//TODO check if there is going to be a UI change here
// if (playbackState == Player.STATE_ENDED) {
// showControls()
// }
// updateButtonVisibilities()
}
override fun onPositionDiscontinuity(#Player.DiscontinuityReason reason: Int) {
if (inErrorState) {
// This will only occur if the user has performed a seek whilst in the error state. Update
// the resume position so that if the user then retries, playback will resume from the
// position to which they seek.
updateResumePosition()
}
}
override fun onPlayerError(e: ExoPlaybackException?) {
var errorString: String? = null
//Check what was the error so that we can show the user what was the correspond problem
if (e?.type == ExoPlaybackException.TYPE_RENDERER) {
val cause = e.rendererException
if (cause is MediaCodecRenderer.DecoderInitializationException) {
// Special case for decoder initialization failures.
errorString = if (cause.decoderName == null) {
when {
cause.cause is MediaCodecUtil.DecoderQueryException -> getString(R.string.error_querying_decoders)
cause.secureDecoderRequired -> getString(R.string.error_no_secure_decoder,
cause.mimeType)
else -> getString(R.string.error_no_decoder,
cause.mimeType)
}
} else {
getString(R.string.error_instantiating_decoder,
cause.decoderName)
}
}
}
if (errorString != null) {
//Show the toast with the proper error
Toast.makeText(activity as Context, errorString, Toast.LENGTH_LONG).show()
}
inErrorState = true
if (isBehindLiveWindow(e)) {
clearResumePosition()
initializePlayer()
} else {
updateResumePosition()
updateRetryButton()
}
}
}
private fun clearResumePosition() {
//Clear the current resume position, since there was an error
currentWindow = C.INDEX_UNSET
playbackPosition = C.TIME_UNSET
}
/*
* This is for the multi window support
* */
private fun isBehindLiveWindow(e: ExoPlaybackException?): Boolean {
if (e?.type != ExoPlaybackException.TYPE_SOURCE) {
return false
}
var cause: Throwable? = e.sourceException
while (cause != null) {
if (cause is BehindLiveWindowException) {
return true
}
cause = cause.cause
}
return false
}
private fun buildMediaSourceWithAds(uri: Uri): MediaSource {
/*
* This content media source is the video itself without the ads
* */
val contentMediaSource = ExtractorMediaSource.Factory(
DefaultHttpDataSourceFactory("BUO-APP")).createMediaSource(uri) //TODO change the user agent
/*
* The method constructs and returns a ExtractorMediaSource for the given uri.
* We simply use a new DefaultHttpDataSourceFactory which only needs a user agent string.
* By default the factory will use a DefaultExtractorFactory for the media source.
* This supports almost all non-adaptive audio and video formats supported on Android. It will recognize our mp3 file and play it nicely.
* */
return AdsMediaSource(
contentMediaSource,
/* adMediaSourceFactory= */ this,
adsLoader,
playerView.overlayFrameLayout,
/* eventListener= */ null, null)
}
override fun onStart() {
super.onStart()
if (Util.SDK_INT > 23) {
initializePlayer()
}
}
override fun onResume() {
super.onResume()
hideSystemUi()
/*
* Starting with API level 24 Android supports multiple windows.
* As our app can be visible but not active in split window mode, we need to initialize the player in onStart.
* Before API level 24 we wait as long as possible until we grab resources, so we wait until onResume before initializing the player.
* */
if ((Util.SDK_INT <= 23 || player == null)) {
initializePlayer()
}
}
}
The ad never shows and if it shows it shows a rendering error E/ExoPlayerImplInternal: Renderer error. which never allows the video to show. I've run the examples from the IMA ads https://developers.google.com/interactive-media-ads/docs/sdks/android/ example code and it doesn't work neither. Does anyone have implemented the Exo Player succesfully with the latest ExoPlayer library version?
Please Help. Thanks!
When on an emulator, be sure to enable gpu rendering on the virtual device
The problem is that the emulator can not render videos. Therefore it wasn't showing the ads or the video. Run the app on a phone and it will work
I am working on YouTubePlayerFragment integration.
while the initialize YouTubePlayer in YouTubePlayerFragment it acquires audio from another app and that particular app stops playing audio ie. PlayMusic.
As User does not touch play button in my app's youtube player it would not acquire audio from another app. so how to avoid such issue and let another app plays the audio?
Here is my Fragment code, written in Kotlin.
class MyVideoFragment : YouTubePlayerFragment() {
lateinit var mPlayer: YouTubePlayer
companion object {
fun newInstance(url: String): TutorialVideoFragment {
val v = TutorialVideoFragment()
val b = Bundle()
b.putString("url", url)
v.init()
v.arguments = b
return v
}
}
private fun init() {
initialize(DEVELOPER_KEY,
object : YouTubePlayer.OnInitializedListener {
override fun onInitializationSuccess(arg0: YouTubePlayer.Provider,
player: YouTubePlayer, wasRestored: Boolean) {
if (!wasRestored) {
player.cueVideo(arguments.getString("url"))
if (player.isPlaying) {
player.pause();
}
player.setShowFullscreenButton(true)
mPlayer = player
}
}
override fun onInitializationFailure(provider: YouTubePlayer.Provider,
errorReason: YouTubeInitializationResult) {
if (errorReason.isUserRecoverableError) {
// errorReason.getErrorDialog(getActivity(), RECOVERY_DIALOG_REQUEST).show();
} else {
val errorMessage = String.format(
getString(R.string.error_player), errorReason.toString())
toast(errorMessage)
}
}
})
}
}
I faced the same issue. setManageAudioFocus(false) is what you need.
You can disable auto gain of audio focus inside your onInitializationSuccess by doing player.setManageAudioFocus(false) but remember you need to manage audio focus manually. You can read about managing audio focus here