diff --git a/musikr/consumer-rules.pro b/musikr/consumer-rules.pro index e69de29bb..107fe2fb4 100644 --- a/musikr/consumer-rules.pro +++ b/musikr/consumer-rules.pro @@ -0,0 +1 @@ +-keep class org.oxycblt.musikr.metadata.NativeInputStream { *; } \ No newline at end of file diff --git a/musikr/proguard-rules.pro b/musikr/proguard-rules.pro index 481bb4348..9847382a8 100644 --- a/musikr/proguard-rules.pro +++ b/musikr/proguard-rules.pro @@ -18,4 +18,6 @@ # If you keep the line number information, uncomment this to # hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file +#-renamesourcefileattribute SourceFile + +-keep class org.oxycblt.musikr.metadata.NativeInputStream { *; } \ No newline at end of file diff --git a/musikr/src/main/cpp/JVMInputStream.cpp b/musikr/src/main/cpp/JVMInputStream.cpp index bbc69b447..677460634 100644 --- a/musikr/src/main/cpp/JVMInputStream.cpp +++ b/musikr/src/main/cpp/JVMInputStream.cpp @@ -40,7 +40,6 @@ JVMInputStream::JVMInputStream(JNIEnv *env, jobject inputStream) : env(env), inp "seekFromCurrent", "(J)V"); inputStreamSeekFromEndMethod = env->GetMethodID(inputStreamClass, "seekFromEnd", "(J)V"); - inputStreamClearMethod = env->GetMethodID(inputStreamClass, "clear", "()V"); inputStreamTellMethod = env->GetMethodID(inputStreamClass, "tell", "()J"); inputStreamLengthMethod = env->GetMethodID(inputStreamClass, "length", "()J"); @@ -107,7 +106,7 @@ void JVMInputStream::seek(TagLib::offset_t offset, Position p) { } void JVMInputStream::clear() { - env->CallVoidMethod(inputStream, inputStreamClearMethod); + // Nothing to do } TagLib::offset_t JVMInputStream::tell() const { diff --git a/musikr/src/main/cpp/JVMInputStream.h b/musikr/src/main/cpp/JVMInputStream.h index d05564b0a..8007535c5 100644 --- a/musikr/src/main/cpp/JVMInputStream.h +++ b/musikr/src/main/cpp/JVMInputStream.h @@ -100,13 +100,11 @@ public: private: JNIEnv *env; jobject inputStream; - jmethodID inputStreamNameMethod; jmethodID inputStreamReadBlockMethod; jmethodID inputStreamIsOpenMethod; jmethodID inputStreamSeekFromBeginningMethod; jmethodID inputStreamSeekFromCurrentMethod; jmethodID inputStreamSeekFromEndMethod; - jmethodID inputStreamClearMethod; jmethodID inputStreamTellMethod; jmethodID inputStreamLengthMethod; diff --git a/musikr/src/main/java/org/oxycblt/musikr/metadata/AndroidInputStream.kt b/musikr/src/main/java/org/oxycblt/musikr/metadata/AndroidInputStream.kt deleted file mode 100644 index 72089f8e1..000000000 --- a/musikr/src/main/java/org/oxycblt/musikr/metadata/AndroidInputStream.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2024 Auxio Project - * AndroidInputStream.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 . - */ - -package org.oxycblt.musikr.metadata - -import android.content.Context -import java.io.FileInputStream -import java.nio.ByteBuffer - -internal class AndroidInputStream(context: Context, fis: FileInputStream) : NativeInputStream { - private val channel = fis.channel - - override fun readBlock(length: Long): ByteArray { - val buffer = ByteBuffer.allocate(length.toInt()) - channel.read(buffer) - return buffer.array() - } - - override fun isOpen(): Boolean { - return channel.isOpen - } - - override fun seekFromBeginning(offset: Long) { - channel.position(offset) - } - - override fun seekFromCurrent(offset: Long) { - channel.position(channel.position() + offset) - } - - override fun seekFromEnd(offset: Long) { - channel.position(channel.size() - offset) - } - - override fun clear() { - // Nothing to clear - } - - override fun tell() = channel.position() - - override fun length() = channel.size() - - fun close() { - channel.close() - } -} diff --git a/musikr/src/main/java/org/oxycblt/musikr/metadata/MetadataExtractor.kt b/musikr/src/main/java/org/oxycblt/musikr/metadata/MetadataExtractor.kt index 0093afb6a..0ac6f2667 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/metadata/MetadataExtractor.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/metadata/MetadataExtractor.kt @@ -28,14 +28,14 @@ internal interface MetadataExtractor { suspend fun extract(fd: ParcelFileDescriptor): Metadata? companion object { - fun from(context: Context): MetadataExtractor = MetadataExtractorImpl(context) + fun new(): MetadataExtractor = MetadataExtractorImpl } } -private class MetadataExtractorImpl(private val context: Context) : MetadataExtractor { +private object MetadataExtractorImpl : MetadataExtractor { override suspend fun extract(fd: ParcelFileDescriptor) = withContext(Dispatchers.IO) { val fis = FileInputStream(fd.fileDescriptor) - TagLibJNI.open(context, fis).also { fis.close() } + TagLibJNI.open(fis).also { fis.close() } } } diff --git a/musikr/src/main/java/org/oxycblt/musikr/metadata/NativeInputStream.kt b/musikr/src/main/java/org/oxycblt/musikr/metadata/NativeInputStream.kt index 26ef1f4b3..e9f49dfe5 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/metadata/NativeInputStream.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/metadata/NativeInputStream.kt @@ -18,25 +18,39 @@ package org.oxycblt.musikr.metadata -/** - * Java interface for the read-only methods in TagLib's IOStream API. - * - * The vast majority of IO shim between Taglib/KTaglib should occur here to minimize JNI calls. - */ -internal interface NativeInputStream { - fun readBlock(length: Long): ByteArray +import java.io.FileInputStream +import java.nio.ByteBuffer - fun isOpen(): Boolean +class NativeInputStream(fis: FileInputStream) { + private val channel = fis.channel - fun seekFromBeginning(offset: Long) + fun readBlock(length: Long): ByteArray { + val buffer = ByteBuffer.allocate(length.toInt()) + channel.read(buffer) + return buffer.array() + } - fun seekFromCurrent(offset: Long) + fun isOpen(): Boolean { + return channel.isOpen + } - fun seekFromEnd(offset: Long) + fun seekFromBeginning(offset: Long) { + channel.position(offset) + } - fun clear() + fun seekFromCurrent(offset: Long) { + channel.position(channel.position() + offset) + } - fun tell(): Long + fun seekFromEnd(offset: Long) { + channel.position(channel.size() - offset) + } - fun length(): Long + fun tell() = channel.position() + + fun length() = channel.size() + + fun close() { + channel.close() + } } diff --git a/musikr/src/main/java/org/oxycblt/musikr/metadata/TagLibJNI.kt b/musikr/src/main/java/org/oxycblt/musikr/metadata/TagLibJNI.kt index a74bcfc93..68a9b472f 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/metadata/TagLibJNI.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/metadata/TagLibJNI.kt @@ -31,12 +31,12 @@ internal object TagLibJNI { * * Note: This method is blocking and should be handled as such if calling from a coroutine. */ - fun open(context: Context, fis: FileInputStream): Metadata? { - val inputStream = AndroidInputStream(context, fis) + fun open(fis: FileInputStream): Metadata? { + val inputStream = NativeInputStream(fis) val tag = openNative(inputStream) inputStream.close() return tag } - private external fun openNative(ioStream: AndroidInputStream): Metadata? + private external fun openNative(ioStream: NativeInputStream): Metadata? } diff --git a/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExtractStep.kt b/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExtractStep.kt index 10d2c4468..4ac823ea8 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExtractStep.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExtractStep.kt @@ -48,7 +48,7 @@ internal interface ExtractStep { fun from(context: Context, storage: Storage): ExtractStep = ExtractStepImpl( context, - MetadataExtractor.from(context), + MetadataExtractor.new(), TagParser.new(), storage.cache, storage.storedCovers)