diff --git a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt index 6f2fde001..24de4dc5f 100644 --- a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt @@ -26,13 +26,14 @@ import io.legado.app.utils.printOnDebug import io.legado.app.utils.servicePendingIntent import io.legado.app.utils.toastOnUi import kotlinx.coroutines.CancellationException -import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.ensureActive import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock +import kotlinx.coroutines.withContext import okhttp3.Response import org.mozilla.javascript.WrappedException import java.io.File @@ -68,32 +69,22 @@ class HttpReadAloudService : BaseReadAloudService(), super.onDestroy() downloadTask?.cancel() exoPlayer.release() + Coroutine.async { + removeCacheFile() + } } override fun play() { pageChanged = false exoPlayer.stop() + exoPlayer.clearMediaItems() + if (!requestFocus()) return if (contentList.isEmpty()) { AppLog.putDebug("朗读列表为空") ReadBook.readAloud() } else { super.play() - kotlin.runCatching { - if (nowSpeak == 0) { - downloadAudio() - } else { - val fileName = md5SpeakFileName(contentList[nowSpeak]) - val file = getSpeakFileAsMd5(fileName) - if (file.exists()) { - playAudio(file) - } else if (!downloadTaskActiveLock.isLocked) { - downloadAudio() - } - } - }.onFailure { - toastOnUi("朗读出错:${it.localizedMessage}") - AppLog.put("朗读出错:${it.localizedMessage}", it) - } + downloadAndPlayAudios() } } @@ -105,21 +96,20 @@ class HttpReadAloudService : BaseReadAloudService(), readAloudNumber += contentList[nowSpeak].length + 1 if (nowSpeak < contentList.lastIndex) { nowSpeak++ - play() } else { nextChapter() } } - private fun downloadAudio() { + private fun downloadAndPlayAudios() { downloadTask?.cancel() downloadTask = execute { downloadTaskActiveLock.withLock { ensureActive() - removeCacheFile() val httpTts = ReadAloud.httpTTS ?: throw NoStackTraceException("tts is null") contentList.forEachIndexed { index, content -> ensureActive() + if (index < nowSpeak) return@forEachIndexed val fileName = md5SpeakFileName(content) val speakText = content.replace(AppPattern.notReadAloudRegex, "") if (speakText.isEmpty()) { @@ -141,13 +131,19 @@ class HttpReadAloudService : BaseReadAloudService(), return@execute } } - if (index == nowSpeak) { - val file = getSpeakFileAsMd5(fileName) - playAudio(file) + val file = getSpeakFileAsMd5(fileName) + val mediaItem = MediaItem.fromUri(Uri.fromFile(file)) + launch(Main) { + exoPlayer.addMediaItem(mediaItem) + if (!exoPlayer.isPlaying && nowSpeak == index) { + exoPlayer.playWhenReady = true + exoPlayer.prepare() + } } } } - }.onError(IO) { + }.onError { + toastOnUi("朗读出错:${it.localizedMessage}") AppLog.put("朗读下载出错\n${it.localizedMessage}", it) } } @@ -193,6 +189,7 @@ class HttpReadAloudService : BaseReadAloudService(), e.printOnDebug() throw e } + is SocketTimeoutException, is ConnectException -> { downloadErrorNo++ if (downloadErrorNo > 5) { @@ -202,6 +199,7 @@ class HttpReadAloudService : BaseReadAloudService(), throw e } } + else -> { downloadErrorNo++ val msg = "tts下载错误\n${e.localizedMessage}" @@ -223,22 +221,6 @@ class HttpReadAloudService : BaseReadAloudService(), return null } - @Synchronized - private fun playAudio(file: File) { - if (requestFocus()) { - launch { - kotlin.runCatching { - val mediaItem = MediaItem.fromUri(Uri.fromFile(file)) - exoPlayer.setMediaItem(mediaItem) - exoPlayer.playWhenReady = true - exoPlayer.prepare() - }.onFailure { - it.printOnDebug() - } - } - } - } - private fun md5SpeakFileName(content: String): String { return MD5Utils.md5Encode16(textChapter?.title ?: "") + "_" + MD5Utils.md5Encode16("${ReadAloud.httpTTS?.url}-|-$speechRate-|-$content") @@ -338,7 +320,7 @@ class HttpReadAloudService : BaseReadAloudService(), downloadTask?.cancel() exoPlayer.stop() speechRate = AppConfig.speechRatePlay + 5 - downloadAudio() + downloadAndPlayAudios() } override fun onPlaybackStateChanged(playbackState: Int) { @@ -347,15 +329,18 @@ class HttpReadAloudService : BaseReadAloudService(), Player.STATE_IDLE -> { // 空闲 } + Player.STATE_BUFFERING -> { // 缓冲中 } + Player.STATE_READY -> { // 准备好 if (pause) return exoPlayer.play() upPlayPos() } + Player.STATE_ENDED -> { // 结束 playErrorNo = 0 @@ -364,6 +349,12 @@ class HttpReadAloudService : BaseReadAloudService(), } } + override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) { + if (reason == Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED) return + upPlayPos() + playNext() + } + override fun onPlayerError(error: PlaybackException) { super.onPlayerError(error) AppLog.put("朗读错误\n${contentList[nowSpeak]}", error)