Просмотр исходного кода

Update MediaSession metadata for car Bluetooth display (#1008)

* Update MediaSession metadata for car Bluetooth display

* Implement `upMediaMetadata` in `BaseReadAloudService` to sync book details and cover art to `MediaSessionCompat`.
* Map book name to title, chapter name to artist, and author to album metadata keys.
* Support displaying current reading content as a subtitle/lyric string.
* Trigger metadata updates across `HttpReadAloudService` and `TTSReadAloudService` during playback and navigation.

* Apply suggestions from code review

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

---------

Co-authored-by: zuohl <zuohldev@gmail.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
zuohl 6 месяцев назад
Родитель
Сommit
f4ba9eeee0

+ 25 - 0
app/src/main/java/io/legado/app/service/BaseReadAloudService.kt

@@ -14,6 +14,7 @@ import android.media.AudioManager
 import android.net.wifi.WifiManager
 import android.os.Bundle
 import android.os.PowerManager
+import android.support.v4.media.MediaMetadataCompat
 import android.support.v4.media.session.MediaSessionCompat
 import android.support.v4.media.session.PlaybackStateCompat
 import android.telephony.PhoneStateListener
@@ -162,6 +163,7 @@ abstract class BaseReadAloudService : BaseService(),
         }.onSuccess {
             if (it.width > 16 && it.height > 16) {
                 cover = it
+                upMediaMetadata()
                 upReadAloudNotification()
             }
         }
@@ -265,6 +267,7 @@ abstract class BaseReadAloudService : BaseService(),
             }
             paragraphStartPos = pos
             launch(Main) {
+                upMediaMetadata()
                 if (play) play() else pageChanged = true
             }
         }.onError {
@@ -345,6 +348,7 @@ abstract class BaseReadAloudService : BaseService(),
                 }
             }
             upTtsProgress(readAloudNumber + 1)
+            upMediaMetadata(showContent = true)
             play()
         } else {
             toLast = true
@@ -371,6 +375,7 @@ abstract class BaseReadAloudService : BaseService(),
                 }
             }
             upTtsProgress(readAloudNumber + 1)
+            upMediaMetadata(showContent = true)
             play()
         } else {
             nextChapter()
@@ -462,6 +467,26 @@ abstract class BaseReadAloudService : BaseService(),
         )
     }
 
+    /**
+     * 更新媒体元数据, 用于车机蓝牙显示
+     * @param showContent 是否显示当前朗读内容作为歌词
+     */
+    internal fun upMediaMetadata(showContent: Boolean = false) {
+        val currentContent = if (showContent && nowSpeak in contentList.indices) {
+            contentList[nowSpeak]
+        } else {
+            null
+        }
+        val metadata = MediaMetadataCompat.Builder()
+            .putBitmap(MediaMetadataCompat.METADATA_KEY_ART, cover)
+            .putText(MediaMetadataCompat.METADATA_KEY_TITLE, ReadBook.book?.name ?: "")
+            .putText(MediaMetadataCompat.METADATA_KEY_ARTIST, textChapter?.title ?: "")
+            .putText(MediaMetadataCompat.METADATA_KEY_ALBUM, ReadBook.book?.author ?: "")
+            .putText(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, currentContent ?: "")
+            .build()
+        mediaSessionCompat.setMetadata(metadata)
+    }
+
     /**
      * 初始化MediaSession, 注册多媒体按钮
      */

+ 1 - 0
app/src/main/java/io/legado/app/service/HttpReadAloudService.kt

@@ -626,6 +626,7 @@ class HttpReadAloudService : BaseReadAloudService(),
         }
         updateNextPos()
         upPlayPos()
+        upMediaMetadata(showContent = true)
     }
 
     override fun onPlayerError(error: PlaybackException) {

+ 1 - 0
app/src/main/java/io/legado/app/service/TTSReadAloudService.kt

@@ -202,6 +202,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener
                     ReadBook.moveToNextPage()
                 }
                 upTtsProgress(readAloudNumber + 1)
+                upMediaMetadata(showContent = true)
             }
         }