diff --git a/README.md b/README.md index 9738fb875..e4457cb6a 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,14 @@ I primarily built Auxio for myself, but you can use it too, I guess. - Storage (`READ_EXTERNAL_STORAGE`): to read and play your media files - Services (`FOREGROUND_SERVICE`, `WAKE_LOCK`): to keep the music playing even if the app itself is in background +## Building + +Auxio relies on a local version of ExoPlayer that enables some extra features. So, the build process is as follows: + +1. Change into the project directory +2. Run `python3 prebuild.py`, which installs ExoPlayer and it's extensions. +3. Build the project normally in Android Studio. + ## Contributing Auxio accepts most contributions as long as they follow the [Contribution Guidelines](/.github/CONTRIBUTING.md). diff --git a/app/build.gradle b/app/build.gradle index 63b9932cc..efa21d646 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -95,7 +95,8 @@ dependencies { // --- THIRD PARTY --- // ExoPlayer - implementation "com.google.android.exoplayer:exoplayer-core:2.16.1" + implementation project(':exoplayer-library-core') + implementation project(':exoplayer-extension-flac') // Image loading implementation 'io.coil-kt:coil:2.0.0-alpha06' diff --git a/app/src/main/java/org/oxycblt/auxio/coil/AuxioFetcher.kt b/app/src/main/java/org/oxycblt/auxio/coil/AuxioFetcher.kt index 07bd896bd..6c2bcf791 100644 --- a/app/src/main/java/org/oxycblt/auxio/coil/AuxioFetcher.kt +++ b/app/src/main/java/org/oxycblt/auxio/coil/AuxioFetcher.kt @@ -18,8 +18,8 @@ import coil.size.pxOrElse 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.metadata.xiph.PictureFrame import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import okio.buffer diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/AudioReactor.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/AudioReactor.kt index 85c65267a..c7a81d6a9 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/system/AudioReactor.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/system/AudioReactor.kt @@ -25,8 +25,8 @@ import androidx.media.AudioAttributesCompat import androidx.media.AudioFocusRequestCompat import androidx.media.AudioManagerCompat import com.google.android.exoplayer2.metadata.Metadata -import com.google.android.exoplayer2.metadata.flac.VorbisComment import com.google.android.exoplayer2.metadata.id3.TextInformationFrame +import com.google.android.exoplayer2.metadata.xiph.VorbisComment import org.oxycblt.auxio.playback.state.PlaybackStateManager import org.oxycblt.auxio.settings.SettingsManager import org.oxycblt.auxio.util.getSystemServiceSafe 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 cae752440..32331bf5d 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 @@ -39,6 +39,7 @@ import com.google.android.exoplayer2.RenderersFactory import com.google.android.exoplayer2.TracksInfo import com.google.android.exoplayer2.audio.AudioAttributes import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer +import com.google.android.exoplayer2.ext.flac.LibflacAudioRenderer import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory import com.google.android.exoplayer2.mediacodec.MediaCodecSelector import com.google.android.exoplayer2.source.DefaultMediaSourceFactory @@ -46,9 +47,8 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.conflate +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.takeWhile import kotlinx.coroutines.launch import org.oxycblt.auxio.BuildConfig @@ -371,7 +371,8 @@ class PlaybackService : Service(), Player.Listener, PlaybackStateManager.Callbac // battery/apk size/cache size val audioRenderer = RenderersFactory { handler, _, audioListener, _, _ -> arrayOf( - MediaCodecAudioRenderer(this, MediaCodecSelector.DEFAULT, handler, audioListener) + MediaCodecAudioRenderer(this, MediaCodecSelector.DEFAULT, handler, audioListener), + LibflacAudioRenderer(handler, audioListener) ) } diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/info/FAQ.md b/info/FAQ.md index 103d3c7fe..28d95654a 100644 --- a/info/FAQ.md +++ b/info/FAQ.md @@ -27,8 +27,8 @@ ability to be extended to music sources outside of local files. You can read mor #### What formats does Auxio support? As per the [Supported ExoPlayer Formats](https://exoplayer.dev/supported-formats.html), Auxio supports -MP4, MP3, MKA, OGG, WAV, MPEG, ACC on all versions of Android. However, FLAC files can only be played -on Android 8.1 and above. Below that, Auxio must be patched with the [FLAC Extension](https://github.com/google/ExoPlayer/tree/release-v2/extensions/flac). +MP4, MP3, MKA, OGG, WAV, MPEG, AAC on all versions of Android. Auxio also supports FLAC on all versions +of Android through the use of the ExoPlayer FLAC extension. #### Why are accents lighter/less saturated in dark mode? diff --git a/prebuild.py b/prebuild.py new file mode 100755 index 000000000..ab3e1b2aa --- /dev/null +++ b/prebuild.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +# This script automatically installs exoplayer with the necessary components. +# This is written in version-agnostic python3, because I'd rather +# not have to deal with the insanity of bash. +import os +import platform +import sys +import subprocess +import re + +FLAC_VERSION = "1.3.2" + +FATAL="\033[1;31m" +WARN="\033[1;91m" +INFO="\033[1;94m" +OK="\033[1;92m" +NC="\033[0m" + +system = platform.system() + +# We do some shell scripting later on, so we can't support windows. +if system not in ["Linux", "Darwin"]: + print("fatal: unsupported platform " + system) + sys.exit(1) + +def sh(cmd): + code = subprocess.call(["sh", "-c", "set -e; " + cmd]) + + if code != 0: + print(FATAL + "fatal:" + NC + " command failed with exit code " + str(code)) + sys.exit(1) + +exoplayer_path = os.path.join(os.path.abspath(os.curdir), "deps", "exoplayer") + +if os.path.exists(exoplayer_path): + reinstall = input(INFO + "info:" + NC + " ExoPlayer is already installed. Would you like to reinstall it? [y/n] ") + + if not re.match("[yY][eE][sS]|[yY]", reinstall): + sys.exit(0) + +ndk_path = os.getenv("NDK_PATH") + +if ndk_path is None or not os.path.isfile(os.path.join(ndk_path, "ndk_build")): + # We don't have a proper path. Do some digging on the Android SDK directory + # to see if we can find it. + if system == "Linux": + ndk_root = os.path.join(os.getenv("HOME"), "Android", "Sdk", "ndk") + elif system == "Darwin": + ndk_root = os.path.join(os.getenv("HOME"), "Library", "Android", "sdk", "ndk") + + candidates = [] + + for entry in os.scandir(ndk_root): + if entry.is_dir(): + candidates.append(entry.path) + + if len(candidates) > 0: + print(WARN + "warn:" + NC + " NDK_PATH was not set or invalid. Multiple candidates were found however:") + + for i, candidate in enumerate(candidates): + print("[" + str(i) + "] " + candidate) + + try: + ndk_path = candidates[int(input("Enter the NDK to use [Default 0]: "))] + except: + ndk_path = candidates[0] + else: + print(FATAL + "fatal:" + NC + " NDK_PATH is either invalid, or the Android NDK was not installed at a recognized location.") + system.exit(1) + +# Now try to install ExoPlayer. +sh("rm -rf deps") + +print(INFO + "info:" + NC + " Cloning ExoPlayer...") +sh("git clone https://github.com/oxygencobalt/ExoPlayer.git " + exoplayer_path) +os.chdir(exoplayer_path) +sh("git checkout release-v2") + +flac_ext_jni_path = os.path.join("extensions", "flac", "src", "main", "jni") +print(INFO + "info:" + NC + " Installing FLAC extension...") +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_path + "/ndk-build APP_ABI=all -j4") + +print(OK + "Prebuild successful." + NC) diff --git a/settings.gradle b/settings.gradle index f5596f2ad..37f1807a0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,4 @@ include ':app' -rootProject.name = "Auxio" \ No newline at end of file +rootProject.name = "Auxio" +gradle.ext.exoplayerModulePrefix = 'exoplayer-' +apply from: file("deps/exoplayer/core_settings.gradle") \ No newline at end of file