迁移到Androidx Media3
This commit is contained in:
+9
-2
@@ -179,8 +179,15 @@ dependencies {
|
|||||||
|
|
||||||
//media
|
//media
|
||||||
implementation("androidx.media:media:1.6.0")
|
implementation("androidx.media:media:1.6.0")
|
||||||
implementation("com.google.android.exoplayer:exoplayer-core:$exoplayer_version")
|
// For media playback using ExoPlayer
|
||||||
implementation("com.google.android.exoplayer:extension-okhttp:$exoplayer_version")
|
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
|
//Splitties
|
||||||
implementation("com.louiscad.splitties:splitties-appctx:$splitties_version")
|
implementation("com.louiscad.splitties:splitties-appctx:$splitties_version")
|
||||||
|
|||||||
Vendored
+1
-1
@@ -239,7 +239,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
## ExoPlayer 反射设置ua 保证该私有变量不被混淆
|
## ExoPlayer 反射设置ua 保证该私有变量不被混淆
|
||||||
-keepclassmembers class com.google.android.exoplayer2.upstream.cache.CacheDataSource$Factory {
|
-keepclassmembers class androidx.media3.datasource.cache.CacheDataSource$Factory {
|
||||||
*** upstreamDataSourceFactory;
|
*** upstreamDataSourceFactory;
|
||||||
}
|
}
|
||||||
## ExoPlayer 如果还不能播放就取消注释这个
|
## ExoPlayer 如果还不能播放就取消注释这个
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package io.legado.app.lib.cronet
|
package io.legado.app.lib.cronet
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.annotation.Keep
|
import androidx.annotation.Keep
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import io.legado.app.utils.DebugLog
|
|
||||||
import okhttp3.Call
|
import okhttp3.Call
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
@@ -12,6 +12,7 @@ import java.io.IOException
|
|||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
@SuppressLint("ObsoleteSdkInt")
|
||||||
@Keep
|
@Keep
|
||||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||||
class NewCallBack(originalRequest: Request, mCall: Call) : AbsCallBack(originalRequest, mCall) {
|
class NewCallBack(originalRequest: Request, mCall: Call) : AbsCallBack(originalRequest, mCall) {
|
||||||
|
|||||||
@@ -1,35 +1,79 @@
|
|||||||
package io.legado.app.help.exoplayer
|
package io.legado.app.help.exoplayer
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.google.android.exoplayer2.MediaItem
|
import androidx.media3.common.MediaItem
|
||||||
import com.google.android.exoplayer2.database.StandaloneDatabaseProvider
|
import androidx.media3.database.StandaloneDatabaseProvider
|
||||||
import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSource
|
import androidx.media3.datasource.DataSource
|
||||||
import com.google.android.exoplayer2.offline.DefaultDownloaderFactory
|
import androidx.media3.datasource.FileDataSource
|
||||||
import com.google.android.exoplayer2.offline.DownloadRequest
|
import androidx.media3.datasource.ResolvingDataSource
|
||||||
import com.google.android.exoplayer2.offline.DownloaderFactory
|
import androidx.media3.datasource.cache.Cache
|
||||||
import com.google.android.exoplayer2.source.MediaSource
|
import androidx.media3.datasource.cache.CacheDataSink
|
||||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource
|
import androidx.media3.datasource.cache.CacheDataSource
|
||||||
import com.google.android.exoplayer2.upstream.DataSource
|
import androidx.media3.datasource.cache.LeastRecentlyUsedCacheEvictor
|
||||||
import com.google.android.exoplayer2.upstream.FileDataSource
|
import androidx.media3.datasource.cache.SimpleCache
|
||||||
import com.google.android.exoplayer2.upstream.cache.*
|
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 io.legado.app.help.http.okHttpClient
|
||||||
import okhttp3.CacheControl
|
import okhttp3.CacheControl
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.lang.reflect.Type
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressLint("UnsafeOptInUsageError")
|
||||||
object ExoPlayerHelper {
|
object ExoPlayerHelper {
|
||||||
|
|
||||||
fun createMediaSource(
|
private const val SPLIT_TAG = "\uD83D\uDEA7"
|
||||||
uri: Uri,
|
|
||||||
defaultRequestProperties: Map<String, String>
|
private val gson by lazy {
|
||||||
): MediaSource {
|
GsonBuilder().create()
|
||||||
val mediaItem = MediaItem.fromUri(uri)
|
}
|
||||||
val mediaSourceFactory = ProgressiveMediaSource.Factory(
|
private val mapType by lazy {
|
||||||
cacheDataSourceFactory.setDefaultRequestProperties(defaultRequestProperties)
|
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
|
* 支持缓存的DataSource.Factory
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import android.content.Intent
|
|||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.media.AudioManager
|
import android.media.AudioManager
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
import android.support.v4.media.MediaMetadataCompat
|
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 android.support.v4.media.session.PlaybackStateCompat
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.media.AudioFocusRequestCompat
|
import androidx.media.AudioFocusRequestCompat
|
||||||
import com.google.android.exoplayer2.DefaultLoadControl
|
import androidx.media3.common.PlaybackException
|
||||||
import com.google.android.exoplayer2.ExoPlayer
|
import androidx.media3.common.Player
|
||||||
import com.google.android.exoplayer2.PlaybackException
|
import androidx.media3.common.util.UnstableApi
|
||||||
import com.google.android.exoplayer2.Player
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
import io.legado.app.base.BaseService
|
import io.legado.app.base.BaseService
|
||||||
import io.legado.app.constant.*
|
import io.legado.app.constant.*
|
||||||
@@ -40,6 +39,7 @@ import kotlinx.coroutines.Dispatchers.Main
|
|||||||
import splitties.systemservices.audioManager
|
import splitties.systemservices.audioManager
|
||||||
import splitties.systemservices.powerManager
|
import splitties.systemservices.powerManager
|
||||||
|
|
||||||
|
@UnstableApi
|
||||||
/**
|
/**
|
||||||
* 音频播放服务
|
* 音频播放服务
|
||||||
*/
|
*/
|
||||||
@@ -74,14 +74,7 @@ class AudioPlayService : BaseService(),
|
|||||||
MediaHelp.buildAudioFocusRequestCompat(this)
|
MediaHelp.buildAudioFocusRequestCompat(this)
|
||||||
}
|
}
|
||||||
private val exoPlayer: ExoPlayer by lazy {
|
private val exoPlayer: ExoPlayer by lazy {
|
||||||
ExoPlayer.Builder(this).setLoadControl(
|
ExoPlayerHelper.createExoPlayer(this)
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
private var mediaSessionCompat: MediaSessionCompat? = null
|
private var mediaSessionCompat: MediaSessionCompat? = null
|
||||||
private var broadcastReceiver: BroadcastReceiver? = null
|
private var broadcastReceiver: BroadcastReceiver? = null
|
||||||
@@ -159,13 +152,14 @@ class AudioPlayService : BaseService(),
|
|||||||
chapter = AudioPlay.durChapter,
|
chapter = AudioPlay.durChapter,
|
||||||
headerMapF = AudioPlay.headers(true),
|
headerMapF = AudioPlay.headers(true),
|
||||||
)
|
)
|
||||||
val uri = Uri.parse(analyzeUrl.url)
|
//val uri = Uri.parse(analyzeUrl.url)
|
||||||
//ExoPlayerHelper.preDownload(uri, analyzeUrl.headerMap)
|
//ExoPlayerHelper.preDownload(uri, analyzeUrl.headerMap)
|
||||||
//休息1秒钟,防止403
|
//休息1秒钟,防止403
|
||||||
//delay(1000)
|
//delay(1000)
|
||||||
val mediaSource = ExoPlayerHelper
|
// val mediaSource = ExoPlayerHelper
|
||||||
.createMediaSource(uri, analyzeUrl.headerMap)
|
// .createMediaSource(uri, analyzeUrl.headerMap)
|
||||||
exoPlayer.setMediaSource(mediaSource)
|
//exoPlayer.setMediaSource(mediaSource)
|
||||||
|
exoPlayer.setMediaItem(ExoPlayerHelper.createMediaItem(analyzeUrl.url,analyzeUrl.headerMap))
|
||||||
exoPlayer.playWhenReady = true
|
exoPlayer.playWhenReady = true
|
||||||
exoPlayer.prepare()
|
exoPlayer.prepare()
|
||||||
}.onError {
|
}.onError {
|
||||||
@@ -234,8 +228,10 @@ class AudioPlayService : BaseService(),
|
|||||||
/**
|
/**
|
||||||
* 调节速度
|
* 调节速度
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private fun upSpeed(adjust: Float) {
|
private fun upSpeed(adjust: Float) {
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
|
@SuppressLint("ObsoleteSdkInt")
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
playSpeed += adjust
|
playSpeed += adjust
|
||||||
exoPlayer.setPlaybackSpeed(playSpeed)
|
exoPlayer.setPlaybackSpeed(playSpeed)
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package io.legado.app.service
|
|||||||
|
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.google.android.exoplayer2.ExoPlayer
|
import androidx.media3.common.MediaItem
|
||||||
import com.google.android.exoplayer2.MediaItem
|
import androidx.media3.common.PlaybackException
|
||||||
import com.google.android.exoplayer2.PlaybackException
|
import androidx.media3.common.Player
|
||||||
import com.google.android.exoplayer2.Player
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
import com.script.ScriptException
|
import com.script.ScriptException
|
||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
import io.legado.app.constant.AppLog
|
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.exception.NoStackTraceException
|
||||||
import io.legado.app.help.config.AppConfig
|
import io.legado.app.help.config.AppConfig
|
||||||
import io.legado.app.help.coroutine.Coroutine
|
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.ReadAloud
|
||||||
import io.legado.app.model.ReadBook
|
import io.legado.app.model.ReadBook
|
||||||
import io.legado.app.model.analyzeRule.AnalyzeUrl
|
import io.legado.app.model.analyzeRule.AnalyzeUrl
|
||||||
@@ -38,7 +39,8 @@ class HttpReadAloudService : BaseReadAloudService(),
|
|||||||
Player.Listener {
|
Player.Listener {
|
||||||
|
|
||||||
private val exoPlayer: ExoPlayer by lazy {
|
private val exoPlayer: ExoPlayer by lazy {
|
||||||
ExoPlayer.Builder(this).build()
|
//ExoPlayer.Builder(this).build()
|
||||||
|
ExoPlayerHelper.createExoPlayer(this)
|
||||||
}
|
}
|
||||||
private val ttsFolderPath: String by lazy {
|
private val ttsFolderPath: String by lazy {
|
||||||
cacheDir.absolutePath + File.separator + "httpTTS" + File.separator
|
cacheDir.absolutePath + File.separator + "httpTTS" + File.separator
|
||||||
|
|||||||
+2
-1
@@ -6,7 +6,8 @@ buildscript {
|
|||||||
build_tool_version = '33.0.1'
|
build_tool_version = '33.0.1'
|
||||||
kotlin_version = '1.8.21'
|
kotlin_version = '1.8.21'
|
||||||
agp_version = '8.0.1'
|
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'
|
splitties_version = '3.0.0'
|
||||||
room_version = '2.5.1'
|
room_version = '2.5.1'
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user