From c1e4d0f10ec5cfb27a4048828b600998b204f766 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Wed, 10 May 2023 17:47:31 -0600 Subject: [PATCH] all: switch to media3 Move everything over to the media3 library instead of ExoPlayer. Media3 is worse in every way. It labels half of ExoPlayer as "unsafe" because it thinks that it's garbage uwu "helpful" abstractions are perfectly servicable when in reality they are a pile of garbage filled with insane performance issues, race conditions, and a seeming lack of awareness to the sheer absurdity of android's media APIs. It is absolutely horrible, but ExoPlayer will stop being maintained soon and I will have to move over for further maintenance. --- .gitmodules | 7 +- CHANGELOG.md | 8 +++ ExoPlayer | 1 - app/build.gradle | 4 +- .../org/oxycblt/auxio/image/ImageModule.kt | 36 ---------- .../auxio/image/extractor/CoverExtractor.kt | 12 ++-- .../auxio/image/extractor/ExtractorModule.kt | 59 +++++++++++++++ .../auxio/music/metadata/TagExtractor.kt | 2 +- .../oxycblt/auxio/music/metadata/TagWorker.kt | 8 +-- .../oxycblt/auxio/music/metadata/TextTags.kt | 8 +-- .../oxycblt/auxio/playback/PlaybackModule.kt | 48 ------------- .../replaygain/ReplayGainAudioProcessor.kt | 12 ++-- .../auxio/playback/system/PlaybackService.kt | 20 +++--- .../auxio/playback/system/SystemModule.kt | 71 +++++++++++++++++++ media | 1 + settings.gradle | 4 +- 16 files changed, 175 insertions(+), 126 deletions(-) delete mode 160000 ExoPlayer create mode 100644 app/src/main/java/org/oxycblt/auxio/image/extractor/ExtractorModule.kt create mode 100644 app/src/main/java/org/oxycblt/auxio/playback/system/SystemModule.kt create mode 160000 media diff --git a/.gitmodules b/.gitmodules index e806f30bf..552a758f6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,3 @@ -[submodule "ExoPlayer"] - path = ExoPlayer - url = https://github.com/OxygenCobalt/ExoPlayer.git - branch = auxio +[submodule "media"] + path = media + url = https://github.com/OxygenCobalt/media.git diff --git a/CHANGELOG.md b/CHANGELOG.md index 59f777a97..53b3d8295 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## dev + +#### What's Fixed +- Fixed issue where vorbis comments in the form of `metadata_block_picture` (lowercase) would not +be parsed as images + +## 3.0.5 + #### What's Fixed - Fixed inconsistent corner radius on widget - Fixed crash that would occur due to intelligent sort name functionality diff --git a/ExoPlayer b/ExoPlayer deleted file mode 160000 index fef2bb3af..000000000 --- a/ExoPlayer +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fef2bb3af622f235d98549ffe2efd8f7f7d2aa41 diff --git a/app/build.gradle b/app/build.gradle index 8870a165b..7f77e603d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -119,8 +119,8 @@ dependencies { // --- THIRD PARTY --- // Exoplayer (Vendored) - implementation project(":exoplayer-library-core") - implementation project(":exoplayer-extension-ffmpeg") + implementation project(":media-lib-exoplayer") + implementation project(":media-lib-decoder-ffmpeg") // Image loading implementation 'io.coil-kt:coil-base:2.2.2' diff --git a/app/src/main/java/org/oxycblt/auxio/image/ImageModule.kt b/app/src/main/java/org/oxycblt/auxio/image/ImageModule.kt index c73af2c73..b3bb1cf2f 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/ImageModule.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/ImageModule.kt @@ -18,16 +18,10 @@ package org.oxycblt.auxio.image -import android.content.Context -import coil.ImageLoader -import coil.request.CachePolicy import dagger.Binds import dagger.Module -import dagger.Provides import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent -import javax.inject.Singleton import org.oxycblt.auxio.image.extractor.* @Module @@ -35,33 +29,3 @@ import org.oxycblt.auxio.image.extractor.* interface ImageModule { @Binds fun settings(imageSettings: ImageSettingsImpl): ImageSettings } - -@Module -@InstallIn(SingletonComponent::class) -class CoilModule { - @Singleton - @Provides - fun imageLoader( - @ApplicationContext context: Context, - songFactory: AlbumCoverFetcher.SongFactory, - albumFactory: AlbumCoverFetcher.AlbumFactory, - artistFactory: ArtistImageFetcher.Factory, - genreFactory: GenreImageFetcher.Factory, - playlistFactory: PlaylistImageFetcher.Factory - ) = - ImageLoader.Builder(context) - .components { - // Add fetchers for Music components to make them usable with ImageRequest - add(MusicKeyer()) - add(songFactory) - add(albumFactory) - add(artistFactory) - add(genreFactory) - add(playlistFactory) - } - // Use our own crossfade with error drawable support - .transitionFactory(ErrorCrossfadeTransitionFactory()) - // Not downloading anything, so no disk-caching - .diskCachePolicy(CachePolicy.DISABLED) - .build() -} diff --git a/app/src/main/java/org/oxycblt/auxio/image/extractor/CoverExtractor.kt b/app/src/main/java/org/oxycblt/auxio/image/extractor/CoverExtractor.kt index 1c2bb113d..83bd50fd5 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/extractor/CoverExtractor.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/extractor/CoverExtractor.kt @@ -20,12 +20,12 @@ package org.oxycblt.auxio.image.extractor import android.content.Context import android.media.MediaMetadataRetriever -import com.google.android.exoplayer2.MediaItem -import com.google.android.exoplayer2.MediaMetadata -import com.google.android.exoplayer2.MetadataRetriever -import com.google.android.exoplayer2.metadata.flac.PictureFrame -import com.google.android.exoplayer2.metadata.id3.ApicFrame -import com.google.android.exoplayer2.source.MediaSource +import androidx.media3.common.MediaItem +import androidx.media3.common.MediaMetadata +import androidx.media3.exoplayer.MetadataRetriever +import androidx.media3.exoplayer.source.MediaSource +import androidx.media3.extractor.metadata.flac.PictureFrame +import androidx.media3.extractor.metadata.id3.ApicFrame import dagger.hilt.android.qualifiers.ApplicationContext import java.io.ByteArrayInputStream import java.io.InputStream diff --git a/app/src/main/java/org/oxycblt/auxio/image/extractor/ExtractorModule.kt b/app/src/main/java/org/oxycblt/auxio/image/extractor/ExtractorModule.kt new file mode 100644 index 000000000..91adba89e --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/image/extractor/ExtractorModule.kt @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 Auxio Project + * ExtractorModule.kt is part of Auxio. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.oxycblt.auxio.image.extractor + +import android.content.Context +import coil.ImageLoader +import coil.request.CachePolicy +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +class ExtractorModule { + @Singleton + @Provides + fun imageLoader( + @ApplicationContext context: Context, + songFactory: AlbumCoverFetcher.SongFactory, + albumFactory: AlbumCoverFetcher.AlbumFactory, + artistFactory: ArtistImageFetcher.Factory, + genreFactory: GenreImageFetcher.Factory, + playlistFactory: PlaylistImageFetcher.Factory + ) = + ImageLoader.Builder(context) + .components { + // Add fetchers for Music components to make them usable with ImageRequest + add(MusicKeyer()) + add(songFactory) + add(albumFactory) + add(artistFactory) + add(genreFactory) + add(playlistFactory) + } + // Use our own crossfade with error drawable support + .transitionFactory(ErrorCrossfadeTransitionFactory()) + // Not downloading anything, so no disk-caching + .diskCachePolicy(CachePolicy.DISABLED) + .build() +} diff --git a/app/src/main/java/org/oxycblt/auxio/music/metadata/TagExtractor.kt b/app/src/main/java/org/oxycblt/auxio/music/metadata/TagExtractor.kt index 60586d9ee..7e31400ff 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/metadata/TagExtractor.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/metadata/TagExtractor.kt @@ -18,7 +18,7 @@ package org.oxycblt.auxio.music.metadata -import com.google.android.exoplayer2.MetadataRetriever +import androidx.media3.exoplayer.MetadataRetriever import javax.inject.Inject import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.yield diff --git a/app/src/main/java/org/oxycblt/auxio/music/metadata/TagWorker.kt b/app/src/main/java/org/oxycblt/auxio/music/metadata/TagWorker.kt index 1a553211c..2a096c789 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/metadata/TagWorker.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/metadata/TagWorker.kt @@ -19,10 +19,10 @@ package org.oxycblt.auxio.music.metadata import androidx.core.text.isDigitsOnly -import com.google.android.exoplayer2.MediaItem -import com.google.android.exoplayer2.MetadataRetriever -import com.google.android.exoplayer2.source.MediaSource -import com.google.android.exoplayer2.source.TrackGroupArray +import androidx.media3.common.MediaItem +import androidx.media3.exoplayer.MetadataRetriever +import androidx.media3.exoplayer.source.MediaSource +import androidx.media3.exoplayer.source.TrackGroupArray import java.util.concurrent.Future import javax.inject.Inject import org.oxycblt.auxio.music.device.RawSong diff --git a/app/src/main/java/org/oxycblt/auxio/music/metadata/TextTags.kt b/app/src/main/java/org/oxycblt/auxio/music/metadata/TextTags.kt index 9b486c623..cecd572ba 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/metadata/TextTags.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/metadata/TextTags.kt @@ -18,10 +18,10 @@ package org.oxycblt.auxio.music.metadata -import com.google.android.exoplayer2.metadata.Metadata -import com.google.android.exoplayer2.metadata.id3.InternalFrame -import com.google.android.exoplayer2.metadata.id3.TextInformationFrame -import com.google.android.exoplayer2.metadata.vorbis.VorbisComment +import androidx.media3.common.Metadata +import androidx.media3.extractor.metadata.id3.InternalFrame +import androidx.media3.extractor.metadata.id3.TextInformationFrame +import androidx.media3.extractor.metadata.vorbis.VorbisComment /** * Processing wrapper for [Metadata] that allows organized access to text-based audio tags. diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackModule.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackModule.kt index 55233002d..36fb9a0ee 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackModule.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackModule.kt @@ -18,25 +18,9 @@ package org.oxycblt.auxio.playback -import android.content.Context -import com.google.android.exoplayer2.extractor.ExtractorsFactory -import com.google.android.exoplayer2.extractor.flac.FlacExtractor -import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor -import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor -import com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor -import com.google.android.exoplayer2.extractor.mp4.Mp4Extractor -import com.google.android.exoplayer2.extractor.ogg.OggExtractor -import com.google.android.exoplayer2.extractor.ts.AdtsExtractor -import com.google.android.exoplayer2.extractor.wav.WavExtractor -import com.google.android.exoplayer2.source.MediaSource -import com.google.android.exoplayer2.source.ProgressiveMediaSource -import com.google.android.exoplayer2.upstream.ContentDataSource -import com.google.android.exoplayer2.upstream.DataSource import dagger.Binds import dagger.Module -import dagger.Provides import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import javax.inject.Singleton import org.oxycblt.auxio.playback.state.PlaybackStateManager @@ -50,35 +34,3 @@ interface PlaybackModule { fun stateManager(playbackManager: PlaybackStateManagerImpl): PlaybackStateManager @Binds fun settings(playbackSettings: PlaybackSettingsImpl): PlaybackSettings } - -@Module -@InstallIn(SingletonComponent::class) -class ExoPlayerModule { - @Provides - fun mediaSourceFactory( - dataSourceFactory: DataSource.Factory, - extractorsFactory: ExtractorsFactory - ): MediaSource.Factory = ProgressiveMediaSource.Factory(dataSourceFactory, extractorsFactory) - - @Provides - fun dataSourceFactory(@ApplicationContext context: Context) = - // We only ever open conte tURIs, so only provide those data sources. - DataSource.Factory { ContentDataSource(context) } - - @Provides - fun extractorsFactory() = ExtractorsFactory { - // Define our own extractors so we can exclude non-audio parsers. - // Ordering is derived from the DefaultExtractorsFactory's optimized ordering: - // https://docs.google.com/document/d/1w2mKaWMxfz2Ei8-LdxqbPs1VLe_oudB-eryXXw9OvQQ. - arrayOf( - FlacExtractor(), - WavExtractor(), - FragmentedMp4Extractor(), - Mp4Extractor(), - OggExtractor(), - MatroskaExtractor(), - // Enable constant bitrate seeking so that certain MP3s/AACs are seekable - AdtsExtractor(AdtsExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING), - Mp3Extractor(Mp3Extractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING)) - } -} diff --git a/app/src/main/java/org/oxycblt/auxio/playback/replaygain/ReplayGainAudioProcessor.kt b/app/src/main/java/org/oxycblt/auxio/playback/replaygain/ReplayGainAudioProcessor.kt index e9015c8d5..fafe5266c 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/replaygain/ReplayGainAudioProcessor.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/replaygain/ReplayGainAudioProcessor.kt @@ -18,12 +18,12 @@ package org.oxycblt.auxio.playback.replaygain -import com.google.android.exoplayer2.C -import com.google.android.exoplayer2.Format -import com.google.android.exoplayer2.Player -import com.google.android.exoplayer2.Tracks -import com.google.android.exoplayer2.audio.AudioProcessor -import com.google.android.exoplayer2.audio.BaseAudioProcessor +import androidx.media3.common.C +import androidx.media3.common.Format +import androidx.media3.common.Player +import androidx.media3.common.Tracks +import androidx.media3.common.audio.AudioProcessor +import androidx.media3.exoplayer.audio.BaseAudioProcessor import java.nio.ByteBuffer import javax.inject.Inject import kotlin.math.pow diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackService.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackService.kt index a03f231fd..e6ae6a8d0 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackService.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackService.kt @@ -26,18 +26,14 @@ import android.content.IntentFilter import android.media.AudioManager import android.media.audiofx.AudioEffect import android.os.IBinder -import com.google.android.exoplayer2.C -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 com.google.android.exoplayer2.RenderersFactory -import com.google.android.exoplayer2.audio.AudioAttributes -import com.google.android.exoplayer2.audio.AudioCapabilities -import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer -import com.google.android.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer -import com.google.android.exoplayer2.mediacodec.MediaCodecSelector -import com.google.android.exoplayer2.source.MediaSource +import androidx.media3.common.* +import androidx.media3.decoder.ffmpeg.FfmpegAudioRenderer +import androidx.media3.exoplayer.ExoPlayer +import androidx.media3.exoplayer.RenderersFactory +import androidx.media3.exoplayer.audio.AudioCapabilities +import androidx.media3.exoplayer.audio.MediaCodecAudioRenderer +import androidx.media3.exoplayer.mediacodec.MediaCodecSelector +import androidx.media3.exoplayer.source.MediaSource import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject import kotlinx.coroutines.CoroutineScope diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/SystemModule.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/SystemModule.kt new file mode 100644 index 000000000..47b052761 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/playback/system/SystemModule.kt @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 Auxio Project + * SystemModule.kt is part of Auxio. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.oxycblt.auxio.playback.system + +import android.content.Context +import androidx.media3.datasource.ContentDataSource +import androidx.media3.datasource.DataSource +import androidx.media3.exoplayer.source.MediaSource +import androidx.media3.exoplayer.source.ProgressiveMediaSource +import androidx.media3.extractor.ExtractorsFactory +import androidx.media3.extractor.flac.FlacExtractor +import androidx.media3.extractor.mkv.MatroskaExtractor +import androidx.media3.extractor.mp3.Mp3Extractor +import androidx.media3.extractor.mp4.FragmentedMp4Extractor +import androidx.media3.extractor.mp4.Mp4Extractor +import androidx.media3.extractor.ogg.OggExtractor +import androidx.media3.extractor.ts.AdtsExtractor +import androidx.media3.extractor.wav.WavExtractor +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent + +@Module +@InstallIn(SingletonComponent::class) +class SystemModule { + @Provides + fun mediaSourceFactory( + dataSourceFactory: DataSource.Factory, + extractorsFactory: ExtractorsFactory + ): MediaSource.Factory = ProgressiveMediaSource.Factory(dataSourceFactory, extractorsFactory) + + @Provides + fun dataSourceFactory(@ApplicationContext context: Context) = + // We only ever open conte tURIs, so only provide those data sources. + DataSource.Factory { ContentDataSource(context) } + + @Provides + fun extractorsFactory() = ExtractorsFactory { + // Define our own extractors so we can exclude non-audio parsers. + // Ordering is derived from the DefaultExtractorsFactory's optimized ordering: + // https://docs.google.com/document/d/1w2mKaWMxfz2Ei8-LdxqbPs1VLe_oudB-eryXXw9OvQQ. + arrayOf( + FlacExtractor(), + WavExtractor(), + FragmentedMp4Extractor(), + Mp4Extractor(), + OggExtractor(), + MatroskaExtractor(), + // Enable constant bitrate seeking so that certain MP3s/AACs are seekable + AdtsExtractor(AdtsExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING), + Mp3Extractor(Mp3Extractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING)) + } +} diff --git a/media b/media new file mode 160000 index 000000000..e01f3be06 --- /dev/null +++ b/media @@ -0,0 +1 @@ +Subproject commit e01f3be069d30d933f3812cf3b51ece791d67510 diff --git a/settings.gradle b/settings.gradle index df2dcbd45..4595c06e6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,4 @@ include ':app' rootProject.name = "Auxio" -gradle.ext.exoplayerModulePrefix = 'exoplayer-' -apply from: file("ExoPlayer/core_settings.gradle") \ No newline at end of file +gradle.ext.androidxMediaModulePrefix = 'media-' +apply from: file("media/core_settings.gradle") \ No newline at end of file