迁移到Androidx Media3

This commit is contained in:
ag2s20150909 2023-05-11 19:53:56 +08:00
parent 81f5340047
commit 134d62cba7
7 changed files with 122 additions and 46 deletions

View File

@ -179,8 +179,15 @@ dependencies {
//media
implementation("androidx.media:media:1.6.0")
implementation("com.google.android.exoplayer:exoplayer-core:$exoplayer_version")
implementation("com.google.android.exoplayer:extension-okhttp:$exoplayer_version")
// For media playback using ExoPlayer
implementation "androidx.media3:media3-exoplayer:$media3_version"
// For loading data using the OkHttp network stack
implementation "androidx.media3:media3-datasource-okhttp:$media3_version"
// For exposing and controlling media sessions
//implementation "androidx.media3:media3-session:$media3_version"
// implementation("com.google.android.exoplayer:exoplayer-core:$exoplayer_version")
// implementation("com.google.android.exoplayer:extension-okhttp:$exoplayer_version")
//Splitties
implementation("com.louiscad.splitties:splitties-appctx:$splitties_version")

View File

@ -239,7 +239,7 @@
}
## ExoPlayer 反射设置ua 保证该私有变量不被混淆
-keepclassmembers class com.google.android.exoplayer2.upstream.cache.CacheDataSource$Factory {
-keepclassmembers class androidx.media3.datasource.cache.CacheDataSource$Factory {
*** upstreamDataSourceFactory;
}
## ExoPlayer 如果还不能播放就取消注释这个

View File

@ -1,9 +1,9 @@
package io.legado.app.lib.cronet
import android.annotation.SuppressLint
import android.os.Build
import androidx.annotation.Keep
import androidx.annotation.RequiresApi
import io.legado.app.utils.DebugLog
import okhttp3.Call
import okhttp3.Request
import okhttp3.Response
@ -12,6 +12,7 @@ import java.io.IOException
import java.util.concurrent.CompletableFuture
import java.util.concurrent.TimeUnit
@SuppressLint("ObsoleteSdkInt")
@Keep
@RequiresApi(api = Build.VERSION_CODES.N)
class NewCallBack(originalRequest: Request, mCall: Call) : AbsCallBack(originalRequest, mCall) {

View File

@ -1,35 +1,79 @@
package io.legado.app.help.exoplayer
import android.annotation.SuppressLint
import android.content.Context
import android.net.Uri
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.database.StandaloneDatabaseProvider
import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSource
import com.google.android.exoplayer2.offline.DefaultDownloaderFactory
import com.google.android.exoplayer2.offline.DownloadRequest
import com.google.android.exoplayer2.offline.DownloaderFactory
import com.google.android.exoplayer2.source.MediaSource
import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.upstream.DataSource
import com.google.android.exoplayer2.upstream.FileDataSource
import com.google.android.exoplayer2.upstream.cache.*
import androidx.media3.common.MediaItem
import androidx.media3.database.StandaloneDatabaseProvider
import androidx.media3.datasource.DataSource
import androidx.media3.datasource.FileDataSource
import androidx.media3.datasource.ResolvingDataSource
import androidx.media3.datasource.cache.Cache
import androidx.media3.datasource.cache.CacheDataSink
import androidx.media3.datasource.cache.CacheDataSource
import androidx.media3.datasource.cache.LeastRecentlyUsedCacheEvictor
import androidx.media3.datasource.cache.SimpleCache
import androidx.media3.datasource.okhttp.OkHttpDataSource
import androidx.media3.exoplayer.DefaultLoadControl
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.offline.DefaultDownloaderFactory
import androidx.media3.exoplayer.offline.DownloadRequest
import androidx.media3.exoplayer.offline.DownloaderFactory
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import io.legado.app.help.http.okHttpClient
import okhttp3.CacheControl
import splitties.init.appCtx
import java.io.File
import java.lang.reflect.Type
import java.util.concurrent.TimeUnit
@SuppressLint("UnsafeOptInUsageError")
object ExoPlayerHelper {
fun createMediaSource(
uri: Uri,
defaultRequestProperties: Map<String, String>
): MediaSource {
val mediaItem = MediaItem.fromUri(uri)
val mediaSourceFactory = ProgressiveMediaSource.Factory(
cacheDataSourceFactory.setDefaultRequestProperties(defaultRequestProperties)
private const val SPLIT_TAG = "\uD83D\uDEA7"
private val gson by lazy {
GsonBuilder().create()
}
private val mapType by lazy {
val type: Type = object : TypeToken<Map<String?, String?>?>() {}.type
type
}
// fun createMediaSource(
// uri: Uri,
// defaultRequestProperties: Map<String, String>
// ): MediaSource {
// val mediaItem = MediaItem.fromUri(uri)
// val mediaSourceFactory = ProgressiveMediaSource.Factory(
// cacheDataSourceFactory.setDefaultRequestProperties(defaultRequestProperties)
// )
// return mediaSourceFactory.createMediaSource(mediaItem)
// }
fun createMediaItem(url: String, headers: Map<String, String>): MediaItem {
val formatUrl = url + SPLIT_TAG + gson.toJson(headers, mapType)
return MediaItem.Builder().setUri(formatUrl).build()
}
fun createExoPlayer(context: Context): ExoPlayer {
return ExoPlayer.Builder(context).setLoadControl(
DefaultLoadControl.Builder().setBufferDurationsMs(
DefaultLoadControl.DEFAULT_MIN_BUFFER_MS,
DefaultLoadControl.DEFAULT_MAX_BUFFER_MS,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS / 10,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS / 10
).build()
)
return mediaSourceFactory.createMediaSource(mediaItem)
.setMediaSourceFactory(
DefaultMediaSourceFactory(context)
.setDataSourceFactory(resolvingDataSource)
.setLiveTargetOffsetMs(5000)
).build()
}
/**
@ -62,6 +106,31 @@ object ExoPlayerHelper {
}
private val resolvingDataSource: ResolvingDataSource.Factory by lazy {
ResolvingDataSource.Factory(
cacheDataSourceFactory
) {
var res = it
if (it.uri.toString().contains(SPLIT_TAG)) {
val urls = it.uri.toString().split(SPLIT_TAG)
val url = urls[0]
res = res.withUri(Uri.parse(url))
try {
val headers: Map<String, String> = gson.fromJson(urls[1], mapType)
res = res.withAdditionalHeaders(headers)
} catch (_: Exception) {
}
}
res
}
}
/**
* 支持缓存的DataSource.Factory
*/

View File

@ -7,7 +7,6 @@ import android.content.Intent
import android.content.IntentFilter
import android.graphics.BitmapFactory
import android.media.AudioManager
import android.net.Uri
import android.os.Build
import android.os.PowerManager
import android.support.v4.media.MediaMetadataCompat
@ -15,10 +14,10 @@ import android.support.v4.media.session.MediaSessionCompat
import android.support.v4.media.session.PlaybackStateCompat
import androidx.core.app.NotificationCompat
import androidx.media.AudioFocusRequestCompat
import com.google.android.exoplayer2.DefaultLoadControl
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.PlaybackException
import com.google.android.exoplayer2.Player
import androidx.media3.common.PlaybackException
import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer
import io.legado.app.R
import io.legado.app.base.BaseService
import io.legado.app.constant.*
@ -40,6 +39,7 @@ import kotlinx.coroutines.Dispatchers.Main
import splitties.systemservices.audioManager
import splitties.systemservices.powerManager
@UnstableApi
/**
* 音频播放服务
*/
@ -74,14 +74,7 @@ class AudioPlayService : BaseService(),
MediaHelp.buildAudioFocusRequestCompat(this)
}
private val exoPlayer: ExoPlayer by lazy {
ExoPlayer.Builder(this).setLoadControl(
DefaultLoadControl.Builder().setBufferDurationsMs(
DefaultLoadControl.DEFAULT_MIN_BUFFER_MS,
DefaultLoadControl.DEFAULT_MAX_BUFFER_MS,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS / 10,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS / 10
).build()
).build()
ExoPlayerHelper.createExoPlayer(this)
}
private var mediaSessionCompat: MediaSessionCompat? = null
private var broadcastReceiver: BroadcastReceiver? = null
@ -159,13 +152,14 @@ class AudioPlayService : BaseService(),
chapter = AudioPlay.durChapter,
headerMapF = AudioPlay.headers(true),
)
val uri = Uri.parse(analyzeUrl.url)
//val uri = Uri.parse(analyzeUrl.url)
//ExoPlayerHelper.preDownload(uri, analyzeUrl.headerMap)
//休息1秒钟防止403
//delay(1000)
val mediaSource = ExoPlayerHelper
.createMediaSource(uri, analyzeUrl.headerMap)
exoPlayer.setMediaSource(mediaSource)
// val mediaSource = ExoPlayerHelper
// .createMediaSource(uri, analyzeUrl.headerMap)
//exoPlayer.setMediaSource(mediaSource)
exoPlayer.setMediaItem(ExoPlayerHelper.createMediaItem(analyzeUrl.url,analyzeUrl.headerMap))
exoPlayer.playWhenReady = true
exoPlayer.prepare()
}.onError {
@ -234,8 +228,10 @@ class AudioPlayService : BaseService(),
/**
* 调节速度
*/
private fun upSpeed(adjust: Float) {
kotlin.runCatching {
@SuppressLint("ObsoleteSdkInt")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
playSpeed += adjust
exoPlayer.setPlaybackSpeed(playSpeed)

View File

@ -2,10 +2,10 @@ package io.legado.app.service
import android.app.PendingIntent
import android.net.Uri
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 androidx.media3.common.MediaItem
import androidx.media3.common.PlaybackException
import androidx.media3.common.Player
import androidx.media3.exoplayer.ExoPlayer
import com.script.ScriptException
import io.legado.app.R
import io.legado.app.constant.AppLog
@ -16,6 +16,7 @@ import io.legado.app.exception.ConcurrentException
import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.config.AppConfig
import io.legado.app.help.coroutine.Coroutine
import io.legado.app.help.exoplayer.ExoPlayerHelper
import io.legado.app.model.ReadAloud
import io.legado.app.model.ReadBook
import io.legado.app.model.analyzeRule.AnalyzeUrl
@ -38,7 +39,8 @@ class HttpReadAloudService : BaseReadAloudService(),
Player.Listener {
private val exoPlayer: ExoPlayer by lazy {
ExoPlayer.Builder(this).build()
//ExoPlayer.Builder(this).build()
ExoPlayerHelper.createExoPlayer(this)
}
private val ttsFolderPath: String by lazy {
cacheDir.absolutePath + File.separator + "httpTTS" + File.separator

View File

@ -6,7 +6,8 @@ buildscript {
build_tool_version = '33.0.1'
kotlin_version = '1.8.21'
agp_version = '8.0.1'
exoplayer_version = '2.18.6'
//exoplayer_version = '2.18.6'
media3_version = "1.0.1"
splitties_version = '3.0.0'
room_version = '2.5.1'
}