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.
This commit is contained in:
Alexander Capehart 2023-05-10 17:47:31 -06:00
parent c6c3816bfc
commit c1e4d0f10e
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
16 changed files with 175 additions and 126 deletions

7
.gitmodules vendored
View file

@ -1,4 +1,3 @@
[submodule "ExoPlayer"] [submodule "media"]
path = ExoPlayer path = media
url = https://github.com/OxygenCobalt/ExoPlayer.git url = https://github.com/OxygenCobalt/media.git
branch = auxio

View file

@ -1,5 +1,13 @@
# Changelog # 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 #### What's Fixed
- Fixed inconsistent corner radius on widget - Fixed inconsistent corner radius on widget
- Fixed crash that would occur due to intelligent sort name functionality - Fixed crash that would occur due to intelligent sort name functionality

@ -1 +0,0 @@
Subproject commit fef2bb3af622f235d98549ffe2efd8f7f7d2aa41

View file

@ -119,8 +119,8 @@ dependencies {
// --- THIRD PARTY --- // --- THIRD PARTY ---
// Exoplayer (Vendored) // Exoplayer (Vendored)
implementation project(":exoplayer-library-core") implementation project(":media-lib-exoplayer")
implementation project(":exoplayer-extension-ffmpeg") implementation project(":media-lib-decoder-ffmpeg")
// Image loading // Image loading
implementation 'io.coil-kt:coil-base:2.2.2' implementation 'io.coil-kt:coil-base:2.2.2'

View file

@ -18,16 +18,10 @@
package org.oxycblt.auxio.image package org.oxycblt.auxio.image
import android.content.Context
import coil.ImageLoader
import coil.request.CachePolicy
import dagger.Binds import dagger.Binds
import dagger.Module import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
import org.oxycblt.auxio.image.extractor.* import org.oxycblt.auxio.image.extractor.*
@Module @Module
@ -35,33 +29,3 @@ import org.oxycblt.auxio.image.extractor.*
interface ImageModule { interface ImageModule {
@Binds fun settings(imageSettings: ImageSettingsImpl): ImageSettings @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()
}

View file

@ -20,12 +20,12 @@ package org.oxycblt.auxio.image.extractor
import android.content.Context import android.content.Context
import android.media.MediaMetadataRetriever import android.media.MediaMetadataRetriever
import com.google.android.exoplayer2.MediaItem import androidx.media3.common.MediaItem
import com.google.android.exoplayer2.MediaMetadata import androidx.media3.common.MediaMetadata
import com.google.android.exoplayer2.MetadataRetriever import androidx.media3.exoplayer.MetadataRetriever
import com.google.android.exoplayer2.metadata.flac.PictureFrame import androidx.media3.exoplayer.source.MediaSource
import com.google.android.exoplayer2.metadata.id3.ApicFrame import androidx.media3.extractor.metadata.flac.PictureFrame
import com.google.android.exoplayer2.source.MediaSource import androidx.media3.extractor.metadata.id3.ApicFrame
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.InputStream import java.io.InputStream

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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()
}

View file

@ -18,7 +18,7 @@
package org.oxycblt.auxio.music.metadata package org.oxycblt.auxio.music.metadata
import com.google.android.exoplayer2.MetadataRetriever import androidx.media3.exoplayer.MetadataRetriever
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.yield import kotlinx.coroutines.yield

View file

@ -19,10 +19,10 @@
package org.oxycblt.auxio.music.metadata package org.oxycblt.auxio.music.metadata
import androidx.core.text.isDigitsOnly import androidx.core.text.isDigitsOnly
import com.google.android.exoplayer2.MediaItem import androidx.media3.common.MediaItem
import com.google.android.exoplayer2.MetadataRetriever import androidx.media3.exoplayer.MetadataRetriever
import com.google.android.exoplayer2.source.MediaSource import androidx.media3.exoplayer.source.MediaSource
import com.google.android.exoplayer2.source.TrackGroupArray import androidx.media3.exoplayer.source.TrackGroupArray
import java.util.concurrent.Future import java.util.concurrent.Future
import javax.inject.Inject import javax.inject.Inject
import org.oxycblt.auxio.music.device.RawSong import org.oxycblt.auxio.music.device.RawSong

View file

@ -18,10 +18,10 @@
package org.oxycblt.auxio.music.metadata package org.oxycblt.auxio.music.metadata
import com.google.android.exoplayer2.metadata.Metadata import androidx.media3.common.Metadata
import com.google.android.exoplayer2.metadata.id3.InternalFrame import androidx.media3.extractor.metadata.id3.InternalFrame
import com.google.android.exoplayer2.metadata.id3.TextInformationFrame import androidx.media3.extractor.metadata.id3.TextInformationFrame
import com.google.android.exoplayer2.metadata.vorbis.VorbisComment import androidx.media3.extractor.metadata.vorbis.VorbisComment
/** /**
* Processing wrapper for [Metadata] that allows organized access to text-based audio tags. * Processing wrapper for [Metadata] that allows organized access to text-based audio tags.

View file

@ -18,25 +18,9 @@
package org.oxycblt.auxio.playback 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.Binds
import dagger.Module import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton import javax.inject.Singleton
import org.oxycblt.auxio.playback.state.PlaybackStateManager import org.oxycblt.auxio.playback.state.PlaybackStateManager
@ -50,35 +34,3 @@ interface PlaybackModule {
fun stateManager(playbackManager: PlaybackStateManagerImpl): PlaybackStateManager fun stateManager(playbackManager: PlaybackStateManagerImpl): PlaybackStateManager
@Binds fun settings(playbackSettings: PlaybackSettingsImpl): PlaybackSettings @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))
}
}

View file

@ -18,12 +18,12 @@
package org.oxycblt.auxio.playback.replaygain package org.oxycblt.auxio.playback.replaygain
import com.google.android.exoplayer2.C import androidx.media3.common.C
import com.google.android.exoplayer2.Format import androidx.media3.common.Format
import com.google.android.exoplayer2.Player import androidx.media3.common.Player
import com.google.android.exoplayer2.Tracks import androidx.media3.common.Tracks
import com.google.android.exoplayer2.audio.AudioProcessor import androidx.media3.common.audio.AudioProcessor
import com.google.android.exoplayer2.audio.BaseAudioProcessor import androidx.media3.exoplayer.audio.BaseAudioProcessor
import java.nio.ByteBuffer import java.nio.ByteBuffer
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.pow import kotlin.math.pow

View file

@ -26,18 +26,14 @@ import android.content.IntentFilter
import android.media.AudioManager import android.media.AudioManager
import android.media.audiofx.AudioEffect import android.media.audiofx.AudioEffect
import android.os.IBinder import android.os.IBinder
import com.google.android.exoplayer2.C import androidx.media3.common.*
import com.google.android.exoplayer2.ExoPlayer import androidx.media3.decoder.ffmpeg.FfmpegAudioRenderer
import com.google.android.exoplayer2.MediaItem import androidx.media3.exoplayer.ExoPlayer
import com.google.android.exoplayer2.PlaybackException import androidx.media3.exoplayer.RenderersFactory
import com.google.android.exoplayer2.Player import androidx.media3.exoplayer.audio.AudioCapabilities
import com.google.android.exoplayer2.RenderersFactory import androidx.media3.exoplayer.audio.MediaCodecAudioRenderer
import com.google.android.exoplayer2.audio.AudioAttributes import androidx.media3.exoplayer.mediacodec.MediaCodecSelector
import com.google.android.exoplayer2.audio.AudioCapabilities import androidx.media3.exoplayer.source.MediaSource
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 dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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))
}
}

1
media Submodule

@ -0,0 +1 @@
Subproject commit e01f3be069d30d933f3812cf3b51ece791d67510

View file

@ -1,4 +1,4 @@
include ':app' include ':app'
rootProject.name = "Auxio" rootProject.name = "Auxio"
gradle.ext.exoplayerModulePrefix = 'exoplayer-' gradle.ext.androidxMediaModulePrefix = 'media-'
apply from: file("ExoPlayer/core_settings.gradle") apply from: file("media/core_settings.gradle")