Răsfoiți Sursa

Merge pull request #1816 from ag2s20150909/master

音频界面显示缓冲进度
kunfei 4 ani în urmă
părinte
comite
7df7b4b7ef

+ 1 - 0
app/src/main/java/io/legado/app/constant/EventBus.kt

@@ -16,6 +16,7 @@ object EventBus {
     const val AUDIO_SUB_TITLE = "audioSubTitle"
     const val AUDIO_STATE = "audioState"
     const val AUDIO_PROGRESS = "audioProgress"
+    const val AUDIO_BUFFER_PROGRESS = "audioBufferProgress"
     const val AUDIO_SIZE = "audioSize"
     const val AUDIO_SPEED = "audioSpeed"
     const val NOTIFY_MAIN = "notifyMain"

+ 8 - 0
app/src/main/java/io/legado/app/help/exoplayer/ExoPlayerHelper.kt

@@ -6,7 +6,9 @@ import com.google.android.exoplayer2.database.StandaloneDatabaseProvider
 import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSource
 import com.google.android.exoplayer2.source.MediaSource
 import com.google.android.exoplayer2.source.ProgressiveMediaSource
+import com.google.android.exoplayer2.upstream.FileDataSource
 import com.google.android.exoplayer2.upstream.cache.Cache
+import com.google.android.exoplayer2.upstream.cache.CacheDataSink
 import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor
 import com.google.android.exoplayer2.upstream.cache.SimpleCache
 import io.legado.app.help.http.okHttpClient
@@ -36,6 +38,12 @@ object ExoPlayerHelper {
         return@lazy OkhttpCacheDataSource.Factory()
             .setCache(cache)
             .setUpstreamDataSourceFactory(okhttpDataFactory)
+            .setCacheReadDataSourceFactory(FileDataSource.Factory())
+            .setCacheWriteDataSinkFactory(
+                CacheDataSink.Factory()
+                    .setCache(cache)
+                    .setFragmentSize(CacheDataSink.DEFAULT_FRAGMENT_SIZE)
+            )
     }
 
     /**

+ 33 - 7
app/src/main/java/io/legado/app/help/exoplayer/OkhttpCacheDataSource.java

@@ -1,8 +1,29 @@
 package io.legado.app.help.exoplayer;
 
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
 import static com.google.android.exoplayer2.util.Util.castNonNull;
 import static java.lang.Math.min;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE_USE;
 
 import android.net.Uri;
 
@@ -37,10 +58,12 @@ import java.io.InterruptedIOException;
 import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
+
 /**
  * A {@link DataSource} that reads and writes a {@link Cache}. Requests are fulfilled from the cache
  * when possible. When data is not cached it is requested from an upstream {@link DataSource} and
@@ -66,8 +89,7 @@ public final class OkhttpCacheDataSource implements DataSource {
         @Nullable
         private PriorityTaskManager upstreamPriorityTaskManager;
         private int upstreamPriority;
-        @OkhttpCacheDataSource.Flags
-        private int flags;
+        private @OkhttpCacheDataSource.Flags int flags;
         @Nullable
         private OkhttpCacheDataSource.EventListener eventListener;
 
@@ -351,6 +373,7 @@ public final class OkhttpCacheDataSource implements DataSource {
      */
     @Documented
     @Retention(RetentionPolicy.SOURCE)
+    @Target(TYPE_USE)
     @IntDef(
             flag = true,
             value = {
@@ -384,8 +407,11 @@ public final class OkhttpCacheDataSource implements DataSource {
      * Reasons the cache may be ignored. One of {@link #CACHE_IGNORED_REASON_ERROR} or {@link
      * #CACHE_IGNORED_REASON_UNSET_LENGTH}.
      */
+    // @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
+    // with Kotlin usages from before TYPE_USE was added.
     @Documented
     @Retention(RetentionPolicy.SOURCE)
+    @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
     @IntDef({CACHE_IGNORED_REASON_ERROR, CACHE_IGNORED_REASON_UNSET_LENGTH})
     public @interface CacheIgnoredReason {
     }
@@ -641,15 +667,15 @@ public final class OkhttpCacheDataSource implements DataSource {
     }
 
     @Override
-    public int read(@NonNull byte[] buffer, int offset, int length) throws IOException {
-        DataSpec requestDataSpec = checkNotNull(this.requestDataSpec);
-        DataSpec currentDataSpec = checkNotNull(this.currentDataSpec);
+    public int read(byte[] buffer, int offset, int length) throws IOException {
         if (length == 0) {
             return 0;
         }
         if (bytesRemaining == 0) {
             return C.RESULT_END_OF_INPUT;
         }
+        DataSpec requestDataSpec = checkNotNull(this.requestDataSpec);
+        DataSpec currentDataSpec = checkNotNull(this.currentDataSpec);
         try {
             if (readPosition >= checkCachePosition) {
                 openNextSource(requestDataSpec, true);
@@ -683,9 +709,8 @@ public final class OkhttpCacheDataSource implements DataSource {
         }
     }
 
-
-    @Nullable
     @Override
+    @Nullable
     public Uri getUri() {
         return actualUri;
     }
@@ -693,6 +718,7 @@ public final class OkhttpCacheDataSource implements DataSource {
     @NonNull
     @Override
     public Map<String, List<String>> getResponseHeaders() {
+        // TODO: Implement.
         return isReadingFromUpstream()
                 ? upstreamDataSource.getResponseHeaders()
                 : Collections.emptyMap();

+ 11 - 1
app/src/main/java/io/legado/app/service/AudioPlayService.kt

@@ -13,6 +13,7 @@ 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
@@ -57,7 +58,14 @@ class AudioPlayService : BaseService(),
         MediaHelp.getFocusRequest(this)
     }
     private val exoPlayer: ExoPlayer by lazy {
-        ExoPlayer.Builder(this).build()
+        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()
     }
     private var mediaSessionCompat: MediaSessionCompat? = null
     private var broadcastReceiver: BroadcastReceiver? = null
@@ -302,6 +310,8 @@ class AudioPlayService : BaseService(),
         upPlayProgressJob = launch {
             while (isActive) {
                 AudioPlay.book?.let {
+                    //更新buffer位置
+                    postEvent(EventBus.AUDIO_BUFFER_PROGRESS, exoPlayer.bufferedPosition.toInt())
                     it.durChapterPos = exoPlayer.currentPosition.toInt()
                     postEvent(EventBus.AUDIO_PROGRESS, it.durChapterPos)
                     saveProgress(it)

+ 4 - 0
app/src/main/java/io/legado/app/ui/book/audio/AudioPlayActivity.kt

@@ -273,6 +273,10 @@ class AudioPlayActivity :
             if (!adjustProgress) binding.playerProgress.progress = it
             binding.tvDurTime.text = progressTimeFormat.format(it.toLong())
         }
+        observeEventSticky<Int>(EventBus.AUDIO_BUFFER_PROGRESS) {
+            binding.playerProgress.secondaryProgress = it
+
+        }
         observeEventSticky<Float>(EventBus.AUDIO_SPEED) {
             binding.tvSpeed.text = String.format("%.1fX", it)
             binding.tvSpeed.visible()