Ship the Android sound packs as Opus
The build encodes TeamSpeak's packs to Ogg Opus at 64 kbps before bundling
them, which takes the sounds from 21.3 MB to 2.0 MB, in the APK and again
once unpacked on the phone. The encoding runs the desktop code's libopus
on the build machine, through a build-only :desktop module compiled from
the same sources as the Maven one.
Both clients play Opus sounds: the sound player (now PackSoundPlayer, as it
no longer plays only wave files) decodes Ogg Opus with the platform's
libopus, and a pack's play("x.wav") finds x.opus, so converted packs keep
their scripts. SoundPackConverter turns any pack folder into Opus.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,20 +4,28 @@ plugins {
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the sound packs of an installed TeamSpeak 3 client into the app's assets, as the
|
||||
* desktop client borrows them from the installation. They are TeamSpeak's and not in the
|
||||
* repository; a build without the client ships no packs.
|
||||
* Puts the sound packs of an installed TeamSpeak 3 client into the app's assets, as the
|
||||
* desktop client borrows them from the installation, with the sounds encoded as Opus
|
||||
* (a fifteenth of the WAVs). They are TeamSpeak's and not in the repository; a build
|
||||
* without the client ships no packs.
|
||||
*/
|
||||
abstract class BundleSoundPacks : DefaultTask() {
|
||||
@get:InputFiles
|
||||
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||
abstract val packs: DirectoryProperty
|
||||
|
||||
/** The desktop code whose libopus does the encoding. */
|
||||
@get:Classpath
|
||||
abstract val encoder: ConfigurableFileCollection
|
||||
|
||||
@get:OutputDirectory
|
||||
abstract val assets: DirectoryProperty
|
||||
|
||||
@get:Inject
|
||||
abstract val exec: ExecOperations
|
||||
|
||||
@TaskAction
|
||||
fun copy() {
|
||||
fun encode() {
|
||||
val out = assets.get().asFile
|
||||
out.deleteRecursively()
|
||||
val source = packs.get().asFile
|
||||
@@ -25,7 +33,20 @@ abstract class BundleSoundPacks : DefaultTask() {
|
||||
logger.warn("No TeamSpeak 3 sound packs at $source; the app ships without sounds")
|
||||
return
|
||||
}
|
||||
source.copyRecursively(File(out, "sound"))
|
||||
exec.javaexec {
|
||||
classpath = encoder
|
||||
mainClass.set("com.ts3client.audio.desktop.EncodeSoundPacks")
|
||||
jvmArgs("--enable-native-access=ALL-UNNAMED")
|
||||
args(source.path, File(out, "sound").path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val soundPackEncoder: Configuration by configurations.creating {
|
||||
isCanBeConsumed = false
|
||||
attributes {
|
||||
attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME))
|
||||
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.JAR))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +56,7 @@ val ts3ClientDir: String = providers.gradleProperty("ts3.client.dir")
|
||||
|
||||
val bundleSoundPacks = tasks.register<BundleSoundPacks>("bundleSoundPacks") {
|
||||
packs.set(File(ts3ClientDir, "sound"))
|
||||
encoder.from(soundPackEncoder)
|
||||
assets.set(layout.buildDirectory.dir("generated/soundPacks"))
|
||||
}
|
||||
|
||||
@@ -87,6 +109,7 @@ android {
|
||||
|
||||
dependencies {
|
||||
implementation(project(":audio"))
|
||||
soundPackEncoder(project(":desktop"))
|
||||
|
||||
implementation(platform(libs.androidx.compose.bom))
|
||||
implementation(libs.androidx.compose.ui)
|
||||
|
||||
20
android/desktop/build.gradle.kts
Normal file
20
android/desktop/build.gradle.kts
Normal file
@@ -0,0 +1,20 @@
|
||||
plugins {
|
||||
`java-library`
|
||||
}
|
||||
|
||||
// The desktop client's platform code, run on the build machine only: its libopus
|
||||
// encodes the sound packs the app ships (see :app's bundleSoundPacks).
|
||||
java {
|
||||
sourceSets["main"].java.setSrcDirs(listOf(rootDir.resolve("../ts3-client/desktop/src/main/java")))
|
||||
sourceSets["main"].resources.setSrcDirs(listOf(rootDir.resolve("../ts3-client/desktop/src/main/resources")))
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile>().configureEach {
|
||||
// The FFM API it reaches libopus through; the build has to run on JDK 25 or newer.
|
||||
options.release = 25
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":core"))
|
||||
}
|
||||
@@ -16,5 +16,5 @@ dependencyResolutionManagement {
|
||||
|
||||
rootProject.name = "ts3-android"
|
||||
|
||||
// core and ts3j compile the very sources the desktop's Maven build does.
|
||||
include(":ts3j", ":core", ":audio", ":app")
|
||||
// core, ts3j and desktop compile the very sources the desktop's Maven build does.
|
||||
include(":ts3j", ":core", ":desktop", ":audio", ":app")
|
||||
|
||||
Reference in New Issue
Block a user