Не удается открыть DummyDataSource: Android ExoPlayer

#android #caching #video-streaming #exoplayer #exoplayer2.x

#Android #кэширование #потоковое видео #exoplayer #exoplayer2.x

Вопрос:

Я пытаюсь транслировать видео с URL-адресов и одновременно сохранять их в кэше.

Я использую DataBaseInspector Android Studio для проверки кэша, и, похоже, он работает, но не все время.

Иногда у меня возникает эта ошибка при попытке воспроизвести видео :

 2021-01-21 10:27:12.956 26648-28069/test.com.test E/ExoPlayerImplInternal: Playback error
      com.google.android.exoplayer2.ExoPlaybackException: Source error
        at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:554)
        at android.os.Handler.dispatchMessage(Handler.java:103)
        at android.os.Looper.loop(Looper.java:238)
        at android.os.HandlerThread.run(HandlerThread.java:67)
     Caused by: java.io.IOException: DummyDataSource cannot be opened
        at com.google.android.exoplayer2.upstream.DummyDataSource.open(DummyDataSource.java:39)
        at com.google.android.exoplayer2.upstream.cache.CacheDataSource.openNextSource(CacheDataSource.java:764)
        at com.google.android.exoplayer2.upstream.cache.CacheDataSource.open(CacheDataSource.java:579)
        at com.google.android.exoplayer2.upstream.StatsDataSource.open(StatsDataSource.java:84)
        at com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractingLoadable.load(ProgressiveMediaPeriod.java:1017)
        at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:415)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:919)
 

При чтении ошибки мы видим исключение IOException, поэтому я проверил путь в кэше, и снова он иногда работает… Ключи, которые я регистрирую во внутренней базе данных exoplayer, — это URL-адреса (я позволяю exoplayer выполнять всю работу, но после я проверил себя).

Вот мой код :

     @Inject
    public VideoCacheManager(@NonNull SimpleCache simpleCache, @ActivityContext Context context) {
        this.simpleCache = simpleCache;
        this.context = context;
        cacheDataSource = new CacheDataSource.Factory();
        cacheDataSource.setCache(simpleCache);
        Log.d(TAG, "VideoCacheManager: cache size left : "   simpleCache.getCacheSpace());
        cacheDataSource.setEventListener(new CacheDataSource.EventListener() {
            @Override
            public void onCachedBytesRead(long cacheSizeBytes, long cachedBytesRead) {
                Log.d(TAG, "onCachedBytesRead: cached bytes read : "   cachedBytesRead);
            }

            @Override
            public void onCacheIgnored(int reason) {
                Log.d(TAG, "onCacheIgnored: cache ignored : "   reason);
            }
        });
    }

    public MediaSource buildMediaSource(MediaItem mediaItem) {
        return new ProgressiveMediaSource.Factory(cacheDataSource).createMediaSource(mediaItem);
    }
 

А SimpleCache — это синглтон, введенный с помощью Hilt :

     @Provides
    @Singleton
    public static SimpleCache simpleCache(@ApplicationContext Context context) {
        return new SimpleCache(context.getApplicationContext().getCacheDir(), leastRecentlyUsedCacheEvictor(), exoDatabaseProvider(context));
    }

    @Provides
    @Singleton
    public static LeastRecentlyUsedCacheEvictor leastRecentlyUsedCacheEvictor() {
        return new LeastRecentlyUsedCacheEvictor(exoPlayerCacheSize());
    }

    @Provides
    @Singleton
    public static Long exoPlayerCacheSize() {
        return (long) (500 * 1024 * 1024);
    }

    @Provides
    @Singleton
    public static ExoDatabaseProvider exoDatabaseProvider(@ApplicationContext Context context) {
        return new ExoDatabaseProvider(context);
    }

 

И в моем классе ExoPlayer у меня есть простой метод :

     public void prepare(MediaItem mediaItem) {
        lastMediaItem = mediaItem;
        Log.d(TAG, "prepare: media item : "   mediaItem.playbackProperties);
        MediaSource mediaSource = videoCacheManager.buildMediaSource(mediaItem);
        Log.d(TAG, "prepare: source : "   mediaSource.getInitialTimeline());
        simpleExoPlayer.prepare(mediaSource);
    }
 

Я достаточно прочитал об exoplayer, и предполагается, что он загружает в кэш видео, если оно не существует, во время первого сеанса потоковой передачи… Итак, что это за ошибка и как ее исправить?

В первый раз, когда я использовал этот код, он сработал, затем я все очистил и повторил попытку без успеха.

Ответ №1:

Хорошо, я просто, должно быть, удалил DefaultDataSourceFactory по ошибке и забыл вернуть an UpstreamDataSource к CacheDataSource экземпляру.

Теперь все работает нормально, надеюсь, это поможет другим.

В коде нам нужно добавить это :

 DefaultDataSourceFactory defaultDataSourceFactory = new DefaultDataSourceFactory(context, Util.getUserAgent(context, context.getString(R.string.app_name)));
cacheDataSource.setUpstreamDataSourceFactory(defaultDataSourceFactory);
 

Я также многое узнал о ExoPlayer просмотре этого видео, несмотря на то, что оно было выпущено в 2018 году с версией exoplayer 2.8.

На данный момент я использую последнюю версию, то есть 2.12.3.