Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ dependencies {

implementation('xyz.gianlu.librespot:librespot-player:1.5.6-SNAPSHOT:thin') {
exclude group: 'xyz.gianlu.librespot', module: 'librespot-sink'
exclude group: 'org.apache.logging.log4j', module: 'log4j-core'
exclude group: 'org.apache.logging.log4j', module: 'log4j-slf4j-impl'
exclude group: 'com.lmax', module: 'disruptor'
exclude group: 'org.apache.logging.log4j'
}
}
1 change: 1 addition & 0 deletions librespot-android-decoder-tremolo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
53 changes: 53 additions & 0 deletions librespot-android-decoder-tremolo/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
plugins {
id 'com.android.library'
}

android {
compileSdkVersion 30
buildToolsVersion "30.0.3"

defaultConfig {
minSdkVersion 23
targetSdkVersion 30
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"

// TODO use modern way to build native library
sourceSets.main {
jniLibs.srcDir 'src/main/libs'
jni.srcDirs = [] //disable automatic ndk-build call
}

// call regular ndk-build(.cmd) script from app directory
task ndkBuild(type: Exec) {
commandLine 'ndk-build.cmd', '-C', file('src/main').absolutePath
}

tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn ndkBuild
}
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

dependencies {
implementation('xyz.gianlu.librespot:librespot-player:1.5.6-SNAPSHOT:thin') {
exclude group: 'xyz.gianlu.librespot', module: 'librespot-sink'
exclude group: 'com.lmax', module: 'disruptor'
exclude group: 'org.apache.logging.log4j'
}
}
3 changes: 3 additions & 0 deletions librespot-android-decoder-tremolo/consumer-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-keepclassmembers class xyz.gianlu.librespot.player.codecs.tremolo.OggDecodingInputStream {
*;
}
25 changes: 25 additions & 0 deletions librespot-android-decoder-tremolo/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

-keepclassmembers class xyz.gianlu.librespot.player.codecs.tremolo.OggDecodingInputStream {
*;
}
1 change: 1 addition & 0 deletions librespot-android-decoder-tremolo/src/main/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
obj
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="xyz.gianlu.librespot.player.codecs.tremolo">

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package xyz.gianlu.librespot.player.codecs;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.IOException;
import java.io.OutputStream;

import xyz.gianlu.librespot.audio.GeneralAudioStream;
import xyz.gianlu.librespot.audio.NormalizationData;
import xyz.gianlu.librespot.player.PlayerConfiguration;
import xyz.gianlu.librespot.player.codecs.tremolo.OggDecodingInputStream;
import xyz.gianlu.librespot.player.codecs.tremolo.SeekableInputStream;
import xyz.gianlu.librespot.player.mixing.output.OutputAudioFormat;

public class TremoloVorbisCodec extends Codec {
private final byte[] buffer = new byte[2 * BUFFER_SIZE];
private final OggDecodingInputStream in;

public TremoloVorbisCodec(@NotNull GeneralAudioStream audioFile, @Nullable NormalizationData normalizationData, @NotNull PlayerConfiguration conf, int duration) throws IOException {
super(audioFile, normalizationData, conf, duration);
seekZero = audioIn.pos();
in = new OggDecodingInputStream(new SeekableInputStream() {
@Override
public void seek(long positionBytes) throws IOException {
audioIn.seek((int) (positionBytes + seekZero));
}

@Override
public long tell() {
return audioIn.pos() - seekZero;
}

@Override
public long length() {
return (audioIn.available() + audioIn.pos()) - seekZero;
}

@Override
public int read(byte[] bytes) throws IOException {
return audioIn.read(bytes);
}

@Override
public void close() {
audioIn.close();
}

@Override
public int read() throws IOException {
return audioIn.read();
}
});

setAudioFormat(new OutputAudioFormat(44100, 16, 2, true, false));
}

@Override
protected synchronized int readInternal(@NotNull OutputStream outputStream) throws IOException {
if (closed) return -1;

int count = in.read(buffer);
if (count == -1)
return -1;

outputStream.write(buffer, 0, count);
outputStream.flush();
return count;
}

@Override
public int time() throws CannotGetTimeException {
if (closed)
throw new CannotGetTimeException("Codec is closed");

return (int) in.tellMs();
}

@Override
public void close() throws IOException {
if (in != null) in.close();
super.close();
}

@Override
public void seek(int positionMs) {
if (!closed) in.seekMs(positionMs);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package xyz.gianlu.librespot.player.codecs.tremolo;

import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;

/**
* Created by M. Lehmann on 15.11.2016.
*/
public class OggDecodingInputStream extends InputStream {
private static final int BUFFER_SIZE = 4096;

static {
System.loadLibrary("tremolo");
}

/**
* address of native OggFileHandle structure
**/
private final long handle;
private final SeekableInputStream oggInputStream;
private final ByteBuffer jniBuffer;

public OggDecodingInputStream(@NotNull SeekableInputStream oggInputStream) throws IOException {
this.oggInputStream = oggInputStream;
this.jniBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE);
this.handle = initDecoder(jniBuffer);
if (handle == 0)
throw new IOException("Couldn't start decoder!");
}

private native long initDecoder(ByteBuffer jniBuffer);

private native int read(long handle, int len);

private native int seekMs(long handle, int milliseconds);

private native int seekSamples(long handle, int samples);

private native long tellMs(long handle);

private native long tellSamples(long handle);

private native long totalSamples(long handle);

private native void close(long handle);

@Override
public synchronized int read() {
jniBuffer.clear();

int size = read(handle, 1);
jniBuffer.limit(size);

byte b = jniBuffer.get();
jniBuffer.clear();
return b;
}

@Override
public synchronized int read(byte[] b, int off, int len) {
len = Math.min(len, BUFFER_SIZE);
jniBuffer.clear();
int size = read(handle, len);
if (size > 0) {
jniBuffer.limit(size);
jniBuffer.get(b, off, size);
jniBuffer.clear();
return size;
}

return -1;
}

@Override
public synchronized int read(byte[] b) {
return this.read(b, 0, b.length);
}

public synchronized int seekMs(int milliseconds) {
return seekMs(handle, milliseconds);
}

public synchronized long tellMs() {
return tellMs(handle);
}

@Override
public synchronized void close() throws IOException {
close(handle);
oggInputStream.close();
super.close();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package xyz.gianlu.librespot.player.codecs.tremolo;

import java.io.IOException;
import java.io.InputStream;

/**
* Created by M. Lehmann on 08.12.2016.
*/
public abstract class SeekableInputStream extends InputStream {

abstract public void seek(long positionBytes) throws IOException;

abstract public long tell() throws IOException;

abstract public long length() throws IOException;

abstract public int read(byte[] bytes) throws IOException;

abstract public void close() throws IOException;
}
1 change: 1 addition & 0 deletions librespot-android-decoder-tremolo/src/main/jni/Android.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include $(wildcard $(call my-dir)/*/Android.mk)
4 changes: 4 additions & 0 deletions librespot-android-decoder-tremolo/src/main/jni/Application.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
APP_PLATFORM := android-14 # proven to work
# TODO: libtremolo _might_ work on x86-devices, you might test it.#
# Otherwise you have to either exclude others or use jorbis for them
APP_ABI := armeabi-v7a arm64-v8a
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := tremolo

LOCAL_SRC_FILES := bitwise.c \
codebook.c \
dsp.c \
floor0.c \
floor1.c \
floor_lookup.c \
framing.c \
mapping0.c \
mdct.c \
misc.c \
res012.c \
treminfo.c \
vorbisfile.c \
hide.c \
tremolo-jni.c \
md5.c

ifeq ($(TARGET_ARCH),arm)
LOCAL_ARM_MODE := arm
LOCAL_SRC_FILES += bitwiseARM.s \
dpen.s \
floor1ARM.s \
mdctARM.s
endif

LOCAL_LDFLAGS += -Wl,--gc-sections

LOCAL_CFLAGS := -ffast-math -O3 -fvisibility=hidden -ffunction-sections -fdata-sections

ifeq ($(TARGET_ARCH),arm)
LOCAL_CFLAGS += -D_ARM_ASSEM_
else
LOCAL_CFLAGS += -DONLY_C
endif

LOCAL_C_INCLUDES:= $(LOCAL_PATH)

include $(BUILD_SHARED_LIBRARY)
Loading