kunfei 4 лет назад
Родитель
Сommit
872c861b61
1 измененных файлов с 60 добавлено и 53 удалено
  1. 60 53
      app/src/main/java/io/legado/app/service/HttpReadAloudService.kt

+ 60 - 53
app/src/main/java/io/legado/app/service/HttpReadAloudService.kt

@@ -1,7 +1,11 @@
 package io.legado.app.service
 
 import android.app.PendingIntent
-import android.media.MediaPlayer
+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 io.legado.app.R
 import io.legado.app.constant.AppLog
 import io.legado.app.constant.AppPattern
@@ -19,21 +23,21 @@ import kotlinx.coroutines.sync.Mutex
 import kotlinx.coroutines.sync.withLock
 import okhttp3.Response
 import org.mozilla.javascript.WrappedException
-
 import java.io.File
-import java.io.FileDescriptor
-import java.io.FileInputStream
 import java.net.ConnectException
 import java.net.SocketTimeoutException
 import java.util.*
 import javax.script.ScriptException
 
+/**
+ * 在线朗读
+ */
 class HttpReadAloudService : BaseReadAloudService(),
-    MediaPlayer.OnPreparedListener,
-    MediaPlayer.OnErrorListener,
-    MediaPlayer.OnCompletionListener {
+    Player.Listener {
 
-    private val mediaPlayer = MediaPlayer()
+    private val exoPlayer: ExoPlayer by lazy {
+        ExoPlayer.Builder(this).build()
+    }
     private val ttsFolderPath: String by lazy {
         cacheDir.absolutePath + File.separator + "httpTTS" + File.separator
     }
@@ -45,19 +49,16 @@ class HttpReadAloudService : BaseReadAloudService(),
 
     override fun onCreate() {
         super.onCreate()
-        mediaPlayer.setOnErrorListener(this)
-        mediaPlayer.setOnPreparedListener(this)
-        mediaPlayer.setOnCompletionListener(this)
+        exoPlayer.addListener(this)
     }
 
     override fun onDestroy() {
         super.onDestroy()
         task?.cancel()
-        mediaPlayer.release()
+        exoPlayer.release()
     }
 
     override fun newReadAloud(play: Boolean) {
-        mediaPlayer.reset()
         playingIndex = -1
         super.newReadAloud(play)
     }
@@ -77,7 +78,7 @@ class HttpReadAloudService : BaseReadAloudService(),
                 } else {
                     val file = getSpeakFileAsMd5(fileName)
                     if (file.exists()) {
-                        playAudio(FileInputStream(file).fd)
+                        playAudio(file)
                     } else {
                         downloadAudio()
                     }
@@ -89,7 +90,7 @@ class HttpReadAloudService : BaseReadAloudService(),
     }
 
     override fun playStop() {
-        mediaPlayer.stop()
+        exoPlayer.stop()
     }
 
     private fun playNext() {
@@ -118,8 +119,7 @@ class HttpReadAloudService : BaseReadAloudService(),
                 if (hasSpeakFile(fileName)) { //已经下载好的语音缓存
                     if (index == nowSpeak) {
                         val file = getSpeakFileAsMd5(fileName)
-                        val fis = FileInputStream(file)
-                        playAudio(fis.fd)
+                        playAudio(file)
                     }
                 } else if (hasSpeakCache(fileName)) { //缓存文件还在,可能还没下载完
                     return@forEachIndexed
@@ -160,9 +160,8 @@ class HttpReadAloudService : BaseReadAloudService(),
                             val file = createSpeakFileAsMd5IfNotExist(fileName)
                             file.writeBytes(bytes)
                             removeSpeakCache(fileName)
-                            val fis = FileInputStream(file)
                             if (index == nowSpeak) {
-                                playAudio(fis.fd)
+                                playAudio(file)
                             }
                         }
                         downloadErrorNo = 0
@@ -213,16 +212,17 @@ class HttpReadAloudService : BaseReadAloudService(),
     }
 
     @Synchronized
-    private fun playAudio(fd: FileDescriptor) {
+    private fun playAudio(file: File) {
         if (playingIndex != nowSpeak && requestFocus()) {
-            try {
-                mediaPlayer.reset()
-                mediaPlayer.setDataSource(fd)
-                mediaPlayer.prepareAsync()
-                playingIndex = nowSpeak
-                postEvent(EventBus.TTS_PROGRESS, readAloudNumber + 1)
-            } catch (e: Exception) {
-                e.printOnDebug()
+            launch {
+                kotlin.runCatching {
+                    val mediaItem = MediaItem.fromUri(Uri.fromFile(file))
+                    exoPlayer.setMediaItem(mediaItem)
+                    exoPlayer.playWhenReady = true
+                    exoPlayer.prepare()
+                }.onFailure {
+                    it.printOnDebug()
+                }
             }
         }
     }
@@ -281,7 +281,7 @@ class HttpReadAloudService : BaseReadAloudService(),
         super.pauseReadAloud(pause)
         kotlin.runCatching {
             playIndexJob?.cancel()
-            mediaPlayer.pause()
+            exoPlayer.pause()
         }
     }
 
@@ -291,7 +291,7 @@ class HttpReadAloudService : BaseReadAloudService(),
             if (playingIndex == -1) {
                 play()
             } else {
-                mediaPlayer.start()
+                exoPlayer.play()
                 upPlayPos()
             }
         }
@@ -302,22 +302,22 @@ class HttpReadAloudService : BaseReadAloudService(),
         val textChapter = textChapter ?: return
         playIndexJob = launch {
             postEvent(EventBus.TTS_PROGRESS, readAloudNumber + 1)
-            if (mediaPlayer.duration <= 0) {
+            if (exoPlayer.duration <= 0) {
                 return@launch
             }
             val speakTextLength = contentList[nowSpeak].length
             if (speakTextLength <= 0) {
                 return@launch
             }
-            val sleep = mediaPlayer.duration / speakTextLength
-            val start = speakTextLength * mediaPlayer.currentPosition / mediaPlayer.duration
+            val sleep = exoPlayer.duration / speakTextLength
+            val start = speakTextLength * exoPlayer.currentPosition / exoPlayer.duration
             for (i in start..contentList[nowSpeak].length) {
                 if (readAloudNumber + i > textChapter.getReadLength(pageIndex + 1)) {
                     pageIndex++
                     ReadBook.moveToNextPage()
                     postEvent(EventBus.TTS_PROGRESS, readAloudNumber + i)
                 }
-                delay(sleep.toLong())
+                delay(sleep)
             }
         }
     }
@@ -327,39 +327,46 @@ class HttpReadAloudService : BaseReadAloudService(),
      */
     override fun upSpeechRate(reset: Boolean) {
         task?.cancel()
-        mediaPlayer.stop()
+        exoPlayer.stop()
         playingIndex = -1
         downloadAudio()
     }
 
-    override fun onPrepared(mp: MediaPlayer?) {
-        super.play()
-        if (pause) return
-        mediaPlayer.start()
-        upPlayPos()
+    override fun onPlaybackStateChanged(playbackState: Int) {
+        super.onPlaybackStateChanged(playbackState)
+        when (playbackState) {
+            Player.STATE_IDLE -> {
+                // 空闲
+            }
+            Player.STATE_BUFFERING -> {
+                // 缓冲中
+            }
+            Player.STATE_READY -> {
+                // 准备好
+                if (pause) return
+                exoPlayer.play()
+                upPlayPos()
+            }
+            Player.STATE_ENDED -> {
+                // 结束
+                playErrorNo = 0
+                playNext()
+            }
+        }
     }
 
     private var playErrorNo = 0
 
-    override fun onError(mp: MediaPlayer?, what: Int, extra: Int): Boolean {
-        if (what == -38 && extra == 0) {
-            play()
-            return true
-        }
-        AppLog.put("朗读错误($what, $extra)\n${contentList[nowSpeak]}")
+    override fun onPlayerError(error: PlaybackException) {
+        super.onPlayerError(error)
+        AppLog.put("朗读错误\n${contentList[nowSpeak]}", error)
         playErrorNo++
         if (playErrorNo >= 5) {
-            toastOnUi("朗读连续5次错误, 最后一次错误代码($what, $extra)")
+            toastOnUi("朗读连续5次错误, 最后一次错误代码(${error.localizedMessage})")
             ReadAloud.pause(this)
         } else {
             playNext()
         }
-        return true
-    }
-
-    override fun onCompletion(mp: MediaPlayer?) {
-        playErrorNo = 0
-        playNext()
     }
 
     override fun aloudServicePendingIntent(actionStr: String): PendingIntent? {