musikr: fix hang on metadata extraction

When files read all the way to EOF.
This commit is contained in:
Alexander Capehart 2025-02-22 21:00:59 -07:00
parent 1d44ce5d71
commit b306456d46
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
3 changed files with 23 additions and 14 deletions

View file

@ -34,7 +34,7 @@ JInputStream::JInputStream(JNIEnv *env, jobject jInputStream) : env(env), jInput
jmethodID jInputStreamNameMethod = jInputStreamClass.method("name", jmethodID jInputStreamNameMethod = jInputStreamClass.method("name",
"()Ljava/lang/String;"); "()Ljava/lang/String;");
jInputStreamReadBlockMethod = jInputStreamClass.method("readBlock", jInputStreamReadBlockMethod = jInputStreamClass.method("readBlock",
"(Ljava/nio/ByteBuffer;)Z"); "(Ljava/nio/ByteBuffer;)I");
jInputStreamIsOpenMethod = jInputStreamClass.method("isOpen", "()Z"); jInputStreamIsOpenMethod = jInputStreamClass.method("isOpen", "()Z");
jInputStreamSeekFromBeginningMethod = jInputStreamClass.method( jInputStreamSeekFromBeginningMethod = jInputStreamClass.method(
"seekFromBeginning", "(J)Z"); "seekFromBeginning", "(J)Z");
@ -58,22 +58,31 @@ TagLib::FileName /* const char * */JInputStream::name() const {
return _name.toCString(true); return _name.toCString(true);
} }
TagLib::ByteVector JInputStream::readBlock(size_t length) { jint JInputStream::readBlockImpl(TagLib::ByteVector &buf) {
// We have to invert the buffer allocation here siits not a perfect system (vykeen instead of korvax0 but i warped all over the hub and i dont think its possible to find a "perfect" purple system like you would withnce the JVM ByteBuffer allocation system
// uses a bugged caching mechanism that leaks memory if used in multithreaded contexts.
TagLib::ByteVector buf { static_cast<unsigned int>(length), 0 };
jobject wrappedByteBuffer = env->NewDirectByteBuffer(buf.data(), jobject wrappedByteBuffer = env->NewDirectByteBuffer(buf.data(),
buf.size()); buf.size());
if (wrappedByteBuffer == nullptr) { if (wrappedByteBuffer == nullptr) {
throw std::runtime_error("Failed to wrap ByteBuffer"); throw std::runtime_error("Failed to wrap ByteBuffer");
} }
JObjectRef byteBuffer = { env, wrappedByteBuffer }; JObjectRef byteBuffer { env, wrappedByteBuffer };
jboolean result = env->CallBooleanMethod(jInputStream, jint read = env->CallIntMethod(jInputStream, jInputStreamReadBlockMethod,
jInputStreamReadBlockMethod, *byteBuffer); *byteBuffer);
if (!result) { return read;
}
TagLib::ByteVector JInputStream::readBlock(size_t length) {
// We have to invert the buffer allocation here
TagLib::ByteVector buf { static_cast<unsigned int>(length), 0 };
jint read = readBlockImpl(buf);
if (read >= 0) {
buf.resize(read);
return buf;
} else if (read == -1) {
buf.resize(0);
return buf;
} else {
throw std::runtime_error("Failed to read block, see logs"); throw std::runtime_error("Failed to read block, see logs");
} }
return buf;
} }
void JInputStream::writeBlock(const TagLib::ByteVector &data) { void JInputStream::writeBlock(const TagLib::ByteVector &data) {

View file

@ -124,6 +124,7 @@ private:
jmethodID jInputStreamSeekFromEndMethod; jmethodID jInputStreamSeekFromEndMethod;
jmethodID jInputStreamTellMethod; jmethodID jInputStreamTellMethod;
jmethodID jInputStreamLengthMethod; jmethodID jInputStreamLengthMethod;
jint readBlockImpl(TagLib::ByteVector &buf);
}; };
#endif //AUXIO_JINPUTSTREAM_H #endif //AUXIO_JINPUTSTREAM_H

View file

@ -28,13 +28,12 @@ internal class NativeInputStream(private val deviceFile: DeviceFile, fis: FileIn
fun name() = requireNotNull(deviceFile.path.name) fun name() = requireNotNull(deviceFile.path.name)
fun readBlock(buf: ByteBuffer): Boolean { fun readBlock(buf: ByteBuffer): Int {
try { try {
channel.read(buf) return channel.read(buf)
return true
} catch (e: Exception) { } catch (e: Exception) {
Log.d("NativeInputStream", "Error reading block", e) Log.d("NativeInputStream", "Error reading block", e)
return false return -2
} }
} }