playback: switch to ffmpeg extension

Switch to the FFMpeg ExoPlayer extension, which should enable support
for ALAC while also retaining support for FLAC below Android 8.
This commit is contained in:
Alexander Capehart 2023-02-13 09:05:36 -07:00
parent c9ddda2ebd
commit 213409924b
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
15 changed files with 40 additions and 33 deletions

View file

@ -4,6 +4,7 @@
#### What's New
- Added support for disc subtitles
- Added support for ALAC files
#### What's Improved
- Auxio will now accept zeroed track/disc numbers in the presence of non-zero total
@ -11,6 +12,7 @@ track/disc fields
- Music loading has been made slightly faster
- Improved sort menu usability
- Fall back to `TXXX:RELEASETYPE` on ID3v2 files
- Switches and checkboxes have been mildly visually refreshed
#### What's Fixed
- Fixed non-functioning "repeat all" repeat mode

View file

@ -127,7 +127,6 @@ dependencies {
kapt "com.google.dagger:dagger-compiler:$dagger_version"
implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
// Testing
debugImplementation "com.squareup.leakcanary:leakcanary-android:2.9.1"
testImplementation "junit:junit:4.13.2"

View file

@ -47,13 +47,13 @@ interface CachedSongsDao {
@TypeConverters(CachedSong.Converters::class)
data class CachedSong(
/**
* The ID of the [Song]'s audio file, obtained from MediaStore. Note that this ID is highly
* The ID of the [RawSong]'s audio file, obtained from MediaStore. Note that this ID is highly
* unstable and should only be used for accessing the audio file.
*/
@PrimaryKey var mediaStoreId: Long,
/** @see RawSong.dateAdded */
var dateAdded: Long,
/** The latest date the [Song]'s audio file was modified, as a unix epoch timestamp. */
/** The latest date the [RawSong]'s audio file was modified, as a unix epoch timestamp. */
var dateModified: Long,
/** @see RawSong.size */
var size: Long? = null,

View file

@ -26,8 +26,6 @@ import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
import org.oxycblt.auxio.music.extractor.CacheRepository
import org.oxycblt.auxio.music.extractor.CacheRepositoryImpl
@Module
@InstallIn(SingletonComponent::class)

View file

@ -15,11 +15,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.music.extractor
package org.oxycblt.auxio.music.cache
import javax.inject.Inject
import org.oxycblt.auxio.music.cache.CachedSong
import org.oxycblt.auxio.music.cache.CachedSongsDao
import org.oxycblt.auxio.music.model.RawSong
import org.oxycblt.auxio.util.*

View file

@ -157,6 +157,8 @@ data class MimeType(val fromExtension: String, val fromFormat: String?) {
MediaFormat.MIMETYPE_AUDIO_VORBIS -> R.string.cdc_vorbis
MediaFormat.MIMETYPE_AUDIO_OPUS -> R.string.cdc_opus
MediaFormat.MIMETYPE_AUDIO_FLAC -> R.string.cdc_flac
// TODO: Add ALAC to this as soon as I can stop using MediaFormat for
// extracting metadata and just use ExoPlayer.
// We don't give a name to more unpopular formats.
else -> -1
}

View file

@ -29,7 +29,7 @@ import java.io.File
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.yield
import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.music.extractor.Cache
import org.oxycblt.auxio.music.cache.Cache
import org.oxycblt.auxio.music.metadata.Date
import org.oxycblt.auxio.music.metadata.parseId3v2PositionField
import org.oxycblt.auxio.music.metadata.transformPositionField

View file

@ -35,7 +35,7 @@ import kotlinx.coroutines.withContext
import kotlinx.coroutines.yield
import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.extractor.*
import org.oxycblt.auxio.music.cache.CacheRepository
import org.oxycblt.auxio.music.metadata.TagExtractor
import org.oxycblt.auxio.music.model.Library
import org.oxycblt.auxio.music.model.RawSong

View file

@ -56,8 +56,10 @@ import org.oxycblt.auxio.util.logD
*/
@AndroidEntryPoint
class IndexerService : Service(), Indexer.Controller, MusicSettings.Listener {
@Inject lateinit var indexer: Indexer
@Inject lateinit var imageLoader: ImageLoader
@Inject lateinit var musicRepository: MusicRepository
@Inject lateinit var indexer: Indexer
@Inject lateinit var musicSettings: MusicSettings
@Inject lateinit var playbackManager: PlaybackStateManager
private val serviceJob = Job()
private val indexScope = CoroutineScope(serviceJob + Dispatchers.IO)
@ -67,8 +69,6 @@ class IndexerService : Service(), Indexer.Controller, MusicSettings.Listener {
private lateinit var observingNotification: ObservingNotification
private lateinit var wakeLock: PowerManager.WakeLock
private lateinit var indexerContentObserver: SystemContentObserver
@Inject lateinit var musicSettings: MusicSettings
@Inject lateinit var imageLoader: ImageLoader
override fun onCreate() {
super.onCreate()

View file

@ -34,7 +34,7 @@ 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.flac.LibflacAudioRenderer
import com.google.android.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory
@ -128,7 +128,7 @@ class PlaybackService :
audioListener,
AudioCapabilities.DEFAULT_AUDIO_CAPABILITIES,
replayGainProcessor),
LibflacAudioRenderer(handler, audioListener, replayGainProcessor))
FfmpegAudioRenderer(handler, audioListener, replayGainProcessor))
}
player =

View file

@ -21,6 +21,7 @@ import android.content.Context
import android.util.AttributeSet
import androidx.annotation.AttrRes
import com.google.android.material.button.MaterialButton
import org.oxycblt.auxio.R
import org.oxycblt.auxio.util.fixDoubleRipple
/**
@ -30,8 +31,11 @@ import org.oxycblt.auxio.util.fixDoubleRipple
*/
open class RippleFixMaterialButton
@JvmOverloads
constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) :
MaterialButton(context, attrs, defStyleAttr) {
constructor(
context: Context,
attrs: AttributeSet? = null,
@AttrRes defStyleAttr: Int = R.attr.materialButtonStyle
) : MaterialButton(context, attrs, defStyleAttr) {
init {
fixDoubleRipple()
}

View file

@ -196,7 +196,6 @@ class WidgetProvider : AppWidgetProvider() {
/**
* Set up the control bar in a [RemoteViews] layout that contains one. This is a kind of
* "floating" drawable that sits in front of the cover and contains the controls.
* @param context [Context] required to set up the view.
*/
private fun RemoteViews.setupBar(): RemoteViews {
// Below API 31, enable a rounded bar only if round mode is enabled.
@ -214,7 +213,6 @@ class WidgetProvider : AppWidgetProvider() {
/**
* Set up the background in a [RemoteViews] layout that contains one. This is largely
* self-explanatory, being a solid-color background that sits behind the cover and controls.
* @param context [Context] required to set up the view.
*/
private fun RemoteViews.setupBackground(): RemoteViews {
// Below API 31, enable a rounded background only if round mode is enabled.

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.materialswitch.MaterialSwitch xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/switchWidget"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

View file

@ -5,6 +5,7 @@
<style name="Widget.Auxio.AppBarLayout" parent="Widget.Material3.AppBarLayout">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<!-- Fix flickering lift animation when scrolling quickly -->
<item name="android:stateListAnimator">@null</item>
</style>

View file

@ -17,10 +17,8 @@ import sys
import subprocess
import re
# WARNING: THE EXOPLAYER VERSION MUST BE KEPT IN LOCK-STEP WITH THE FLAC EXTENSION AND
# WARNING: THE EXOPLAYER VERSION MUST BE KEPT IN LOCK-STEP WITH THE FFMPEG EXTENSION AND
# THE GRADLE DEPENDENCY. IF NOT, VERY UNFRIENDLY BUILD FAILURES AND CRASHES MAY ENSUE.
# EXO_VERSION = "2.18.2"
FLAC_VERSION = "1.3.2"
OK="\033[1;32m" # Bold green
FATAL="\033[1;31m" # Bold red
@ -102,18 +100,26 @@ sh("git clone https://github.com/OxygenCobalt/ExoPlayer.git " + exoplayer_path)
os.chdir(exoplayer_path)
sh("git checkout auxio")
print(INFO + "info:" + NC + " assembling flac extension...")
flac_ext_aar_path = os.path.join(exoplayer_path, "extensions", "flac",
"buildout", "outputs", "aar", "extension-flac-release.aar")
flac_ext_jni_path = os.path.join("extensions", "flac", "src", "main", "jni")
print(INFO + "info:" + NC + " assembling ffmpeg extension...")
if system == "Linux":
host = "linux-x86_64"
elif system == "Darwin":
host = "darwin-x86_64"
os.chdir(flac_ext_jni_path)
sh('curl "https://ftp.osuosl.org/pub/xiph/releases/flac/flac-' + FLAC_VERSION +
'.tar.xz" | tar xJ && mv "flac-' + FLAC_VERSION + '" flac')
sh(ndk_build_path + " APP_ABI=all -j4")
ffmpeg_ext_path = os.path.join(exoplayer_path, "extensions", "ffmpeg", "src", "main")
ffmpeg_ext_aar_path = os.path.join(exoplayer_path, "extensions", "ffmpeg", "buildout", "outputs", "aar", "extension-ffmpeg-release.aar")
ffmpeg_ext_jni_path = os.path.join(exoplayer_path, "extensions", "ffmpeg", "src", "main", "jni")
ffmpeg_src_path = os.path.join(ffmpeg_ext_jni_path, "ffmpeg")
os.chdir(ffmpeg_ext_jni_path)
sh("git clone git://source.ffmpeg.org/ffmpeg ffmpeg")
os.chdir(ffmpeg_src_path)
sh("git checkout release/4.2")
os.chdir(ffmpeg_ext_jni_path)
sh('./build_ffmpeg.sh "' + ffmpeg_ext_path + '" "' + ndk_path + '" "' + host + '" "' + "flac" + '" "' + "alac" + '"')
os.chdir(exoplayer_path)
sh("./gradlew extension-flac:bundleReleaseAar")
sh("./gradlew extension-ffmpeg:bundleReleaseAar")
print(INFO + "info:" + NC + " assembling extractor component...")
@ -124,7 +130,7 @@ sh("./gradlew library-extractor:bundleReleaseAar")
os.chdir(start_path)
sh("mkdir " + libs_path)
sh("cp " + flac_ext_aar_path + " " + libs_path)
sh("cp " + ffmpeg_ext_aar_path + " " + libs_path)
sh("cp " + extractor_aar_path + " " + libs_path)
print(OK + "success:" + NC + " completed pre-build")