diff --git a/library/src/module_core/java/com/chuhai/core/download/DownloadException.kt b/library/src/module_core/java/com/chuhai/core/download/DownloadException.kt new file mode 100644 index 000000000..2ba493348 --- /dev/null +++ b/library/src/module_core/java/com/chuhai/core/download/DownloadException.kt @@ -0,0 +1,17 @@ +package com.chuhai.core.download + +import com.chuhai.core.exceptions.SuperException + +/** + * Created by Max on 2022/5/12 21:05 + * Desc:下载异常 + **/ +class DownloadException : SuperException { + + constructor(message: String) : super(message) + + constructor(throwable: Throwable) : super( + throwable + ) { + } +} \ No newline at end of file diff --git a/library/src/module_core/java/com/chuhai/core/download/DownloadListener.kt b/library/src/module_core/java/com/chuhai/core/download/DownloadListener.kt new file mode 100644 index 000000000..add6e4c81 --- /dev/null +++ b/library/src/module_core/java/com/chuhai/core/download/DownloadListener.kt @@ -0,0 +1,21 @@ +package com.chuhai.core.download + +import java.io.File + + +/** + * Created by Max on 3/6/21 10:29 AM + * Desc:下载监听器 + */ +interface DownloadListener { + + /** + * 下载完成 + */ + fun onDownloadCompleted(result: File) {} + + /** + * 下载异常 + */ + fun onDownloadError(exception: DownloadException) {} +} \ No newline at end of file diff --git a/library/src/module_core/java/com/chuhai/core/player/IPlayer.kt b/library/src/module_core/java/com/chuhai/core/player/IPlayer.kt index 7bb02f6c2..0318b23bc 100644 --- a/library/src/module_core/java/com/chuhai/core/player/IPlayer.kt +++ b/library/src/module_core/java/com/chuhai/core/player/IPlayer.kt @@ -13,7 +13,7 @@ interface IPlayer : ICleared { /** * 绑定页面生命周期 */ - fun bindingLifeCycle(lifecycleOwner: LifecycleOwner) + fun bindLifeCycle(lifecycleOwner: LifecycleOwner) /** * 加载视频源(加载后根据playWhenReady觉得是否播放) diff --git a/library/src/module_core/java/com/chuhai/core/player/download/GlideDownload.kt b/library/src/module_core/java/com/chuhai/core/player/download/GlideDownload.kt new file mode 100644 index 000000000..0c840b46f --- /dev/null +++ b/library/src/module_core/java/com/chuhai/core/player/download/GlideDownload.kt @@ -0,0 +1,60 @@ +package com.chuhai.core.player.download + +import android.graphics.drawable.Drawable +import com.bumptech.glide.Glide +import com.bumptech.glide.request.target.CustomTarget +import com.bumptech.glide.request.transition.Transition +import com.chuhai.core.download.DownloadException +import com.chuhai.core.download.DownloadListener +import com.chuhai.utils.AppUtils +import com.chuhai.utils.log.ILog +import java.io.File + +/** + * Created by Max on 2023/11/3 12:11 + * Desc:Glide 实现下载器功能 + * PS:没有在项目中找到下载器组件,之前的VAP视频是通过Glide下载的,这里暂且也采用这种方式,后续考虑搞个独立的下载组件!! + * TODO ⚠️写好后还未测试验证是否有bug + **/ +class GlideDownload(private val timeout: Int = 15000) : MediaDownloader, ILog { + + private val targetList: ArrayList> by lazy { + ArrayList() + } + + override fun download(url: String, listener: DownloadListener) { + val target = object : CustomTarget() { + override fun onResourceReady(resource: File, transition: Transition?) { + targetList.remove(this) + listener.onDownloadCompleted(resource) + } + + override fun onLoadFailed(errorDrawable: Drawable?) { + super.onLoadFailed(errorDrawable) + targetList.remove(this) + listener.onDownloadError(DownloadException("下载失败")) + } + + override fun onLoadCleared(placeholder: Drawable?) { + } + } + Glide.with(AppUtils.getApp()) + .asFile() + .dontTransform() + .timeout(timeout) + .load(url).into(target) + targetList.add(target) + } + + override fun onCleared() { + super.onCleared() + try { + targetList.forEach { + Glide.with(AppUtils.getApp()).clear(it) + } + } catch (e: Exception) { + e.printStackTrace() + } + targetList.clear() + } +} diff --git a/library/src/module_core/java/com/chuhai/core/player/download/MediaDownloader.kt b/library/src/module_core/java/com/chuhai/core/player/download/MediaDownloader.kt new file mode 100644 index 000000000..e2734f4a1 --- /dev/null +++ b/library/src/module_core/java/com/chuhai/core/player/download/MediaDownloader.kt @@ -0,0 +1,23 @@ +package com.chuhai.core.player.download + +import com.chuhai.core.download.DownloadListener +import com.chuhai.utils.ICleared + +/** + * Created by Max on 2023/11/3 12:45 + * Desc:媒体资源下载器 + */ +interface MediaDownloader : ICleared { + + /** + * 下载 + */ + fun download(url: String, listener: DownloadListener) + + /** + * 释放 + */ + override fun onCleared() { + super.onCleared() + } +} \ No newline at end of file diff --git a/library/src/module_core/java/com/chuhai/core/player/exo/ExoPlayer.kt b/library/src/module_core/java/com/chuhai/core/player/exo/ExoPlayer.kt index 185d3d9c1..21b0c01d9 100644 --- a/library/src/module_core/java/com/chuhai/core/player/exo/ExoPlayer.kt +++ b/library/src/module_core/java/com/chuhai/core/player/exo/ExoPlayer.kt @@ -3,12 +3,15 @@ package com.chuhai.core.player.exo import android.content.Context import android.util.AttributeSet import android.view.View +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.LifecycleOwner import com.chuhai.core.player.IPlayer -import com.chuhai.core.player.PlayerListener -import com.chuhai.core.player.PlayerMediaItem import com.chuhai.core.player.PlaybackState import com.chuhai.core.player.PlayerException +import com.chuhai.core.player.PlayerListener +import com.chuhai.core.player.PlayerMediaItem +import com.google.android.exoplayer2.DefaultLoadControl import com.google.android.exoplayer2.MediaItem import com.google.android.exoplayer2.PlaybackException import com.google.android.exoplayer2.Player @@ -20,7 +23,7 @@ import com.google.android.exoplayer2.ExoPlayer as ExoPlayerImpl * Created by Max on 2023/11/2 14:50 * Desc:基于Exo **/ -class ExoPlayer : StyledPlayerView, IPlayer { +class ExoPlayer : StyledPlayerView, IPlayer, LifecycleEventObserver { private var currentItem: ExoMediaItem? = null @@ -30,6 +33,9 @@ class ExoPlayer : StyledPlayerView, IPlayer { private var listenerAdapter: Player.Listener? = null + // 操作的记录(用于感知生命周期恢复播放或其他场景的判断) + private var playWhenReadyBackup = getPlayWhenReady() + constructor(context: Context) : this(context, null) constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( @@ -37,11 +43,23 @@ class ExoPlayer : StyledPlayerView, IPlayer { attrs, defStyleAttr ) { - player = ExoPlayerImpl.Builder(context).build() + /** + * 缓冲策略:目前先用默认的,后续结合需求场景再调整 + */ + val loadControl = DefaultLoadControl.Builder() + .setBufferDurationsMs( + DefaultLoadControl.DEFAULT_MIN_BUFFER_MS, + DefaultLoadControl.DEFAULT_MAX_BUFFER_MS, + DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS, + DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS + ).build() + player = ExoPlayerImpl.Builder(context).setLoadControl(loadControl).build() + useController = false setPlayer(player) } - override fun bindingLifeCycle(lifecycleOwner: LifecycleOwner) { + override fun bindLifeCycle(lifecycleOwner: LifecycleOwner) { + lifecycleOwner.lifecycle.addObserver(this) } override fun prepare(item: PlayerMediaItem) { @@ -60,6 +78,7 @@ class ExoPlayer : StyledPlayerView, IPlayer { override fun setPlayWhenReady(playWhenReady: Boolean) { this.player.playWhenReady = playWhenReady + this.playWhenReadyBackup = playWhenReady } override fun getPlayWhenReady(): Boolean { @@ -133,4 +152,21 @@ class ExoPlayer : StyledPlayerView, IPlayer { this.currentItem?.onCleared() this.currentItem = null } + + override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { + // TODO 这个方法的代码 还未进行测试,目前需求貌似用不上,后续需要再验证! + when (event) { + Lifecycle.Event.ON_RESUME -> { + setPlayWhenReady(playWhenReadyBackup) + } + + Lifecycle.Event.ON_PAUSE -> { + player.playWhenReady = false + } + + Lifecycle.Event.ON_DESTROY -> { + onCleared() + } + } + } } \ No newline at end of file