diff --git a/jme3-android-native/src/native/jme_decode/com_jme3_audio_plugins_NativeVorbisFile.c b/jme3-android-native/src/native/jme_decode/com_jme3_audio_plugins_NativeVorbisFile.c index ceebbd81ba..25a15f5b8a 100644 --- a/jme3-android-native/src/native/jme_decode/com_jme3_audio_plugins_NativeVorbisFile.c +++ b/jme3-android-native/src/native/jme_decode/com_jme3_audio_plugins_NativeVorbisFile.c @@ -110,13 +110,18 @@ static int FileDesc_seek(void *datasource, ogg_int64_t offset, int whence) wrapper->current = actual_offset; } -static int FileDesc_close(void *datasource) +static int FileDesc_clear(void *datasource) { FileDescWrapper* wrapper = (FileDescWrapper*)datasource; - LOGI("FD close"); - - return close(wrapper->fd); + LOGI("Clear resources -- delegating closure to the Android ParcelFileDescriptor"); + + /* release the file descriptor wrapper buffer */ + free(wrapper); + + wrapper = NULL; + + return 0; } static long FileDesc_tell(void *datasource) @@ -139,7 +144,7 @@ static long FileDesc_tell(void *datasource) static ov_callbacks FileDescCallbacks = { FileDesc_read, FileDesc_seek, - FileDesc_close, + FileDesc_clear, FileDesc_tell }; @@ -157,10 +162,10 @@ static jfieldID nvf_field_bitRate; static jfieldID nvf_field_totalBytes; static jfieldID nvf_field_duration; -JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_nativeInit +JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_preInit (JNIEnv *env, jclass clazz) { - LOGI("nativeInit"); + LOGI("preInit"); nvf_field_ovf = (*env)->GetFieldID(env, clazz, "ovf", "Ljava/nio/ByteBuffer;");; nvf_field_seekable = (*env)->GetFieldID(env, clazz, "seekable", "Z"); @@ -171,10 +176,10 @@ JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_nativeInit nvf_field_duration = (*env)->GetFieldID(env, clazz, "duration", "F"); } -JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_open +JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_init (JNIEnv *env, jobject nvf, jint fd, jlong off, jlong len) { - LOGI("open: fd = %d, off = %lld, len = %lld", fd, off, len); + LOGI("init: fd = %d, off = %lld, len = %lld", fd, off, len); OggVorbis_File* ovf = (OggVorbis_File*) malloc(sizeof(OggVorbis_File)); @@ -189,19 +194,19 @@ JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_open if (result != 0) { - LOGI("ov_open fail"); + LOGI("init fail"); free(ovf); free(wrapper); char err[512]; - sprintf(err, "ov_open failed: %d", result); + sprintf(err, "init failed: %d", result); throwIOException(env, err); return; } - LOGI("ov_open OK"); + LOGI("init OK"); jobject ovfBuf = (*env)->NewDirectByteBuffer(env, ovf, sizeof(OggVorbis_File)); vorbis_info* info = ov_info(ovf, -1); @@ -246,7 +251,7 @@ JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_seekTime } } -JNIEXPORT jint JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_read +JNIEXPORT jint JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_readIntoArray (JNIEnv *env, jobject nvf, jbyteArray buf, jint off, jint len) { int bitstream = -1; @@ -288,7 +293,7 @@ JNIEXPORT jint JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_read return result; } -JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_readFully +JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_readIntoBuffer (JNIEnv *env, jobject nvf, jobject buf) { int bitstream = -1; @@ -330,19 +335,19 @@ JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_readFully } } -JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_close +JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_clearResources (JNIEnv *env, jobject nvf) { - LOGI("close"); + LOGI("clearResources"); jobject ovfBuf = (*env)->GetObjectField(env, nvf, nvf_field_ovf); OggVorbis_File* ovf = (OggVorbis_File*) (*env)->GetDirectBufferAddress(env, ovfBuf); - FileDescWrapper* wrapper = (FileDescWrapper*) ovf->datasource; - wrapper->env = env; + /* release the ovf resources */ ov_clear(ovf); - - free(wrapper); + /* release the ovf buffer */ free(ovf); + ovf = NULL; + /* destroy the java reference object */ (*env)->SetObjectField(env, nvf, nvf_field_ovf, NULL); } diff --git a/jme3-android/src/main/java/com/jme3/audio/plugins/NativeVorbisFile.java b/jme3-android/src/main/java/com/jme3/audio/plugins/NativeVorbisFile.java index bd6ecc6273..9af1e62cbe 100644 --- a/jme3-android/src/main/java/com/jme3/audio/plugins/NativeVorbisFile.java +++ b/jme3-android/src/main/java/com/jme3/audio/plugins/NativeVorbisFile.java @@ -1,8 +1,49 @@ +/* + * Copyright (c) 2009-2023 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package com.jme3.audio.plugins; import java.io.IOException; import java.nio.ByteBuffer; +/** + * Represents the android implementation for the native vorbis file decoder. + * This decoder initializes an OggVorbis_File from an already opened file designated by the {@link NativeVorbisFile#fd}. + *
+ * + * Code by Kirill Vainer. + *
+ * + * Modified by pavl_g. + */ public class NativeVorbisFile { public int fd; @@ -16,22 +57,68 @@ public class NativeVorbisFile { static { System.loadLibrary("decodejme"); - nativeInit(); + preInit(); } - public NativeVorbisFile(int fd, long off, long len) throws IOException { - open(fd, off, len); + /** + * Initializes an ogg vorbis native file from a file descriptor [fd] of an already opened file. + * + * @param fd an integer representing the file descriptor + * @param offset an integer indicating the start of the buffer + * @param length an integer indicating the end of the buffer + * @throws IOException in cases of a failure to initialize the vorbis file + */ + public NativeVorbisFile(int fd, long offset, long length) throws IOException { + init(fd, offset, length); } - private native void open(int fd, long off, long len) throws IOException; - + /** + * Seeks to a playback time relative to the decompressed pcm (Pulse-code modulation) stream. + * + * @param time the playback seek time + * @throws IOException if the seek is not successful + */ public native void seekTime(double time) throws IOException; - public native int read(byte[] buf, int off, int len) throws IOException; + /** + * Reads the vorbis file into a primitive byte buffer [buf] with an [offset] indicating the start byte and a [length] indicating the end byte on the output buffer. + * + * @param buffer a primitive byte buffer to read the data into it + * @param offset an integer representing the offset or the start byte on the output buffer + * @param length an integer representing the end byte on the output buffer + * @return the number of the read bytes, (-1) if the reading has failed indicating an EOF, + * returns (0) if the reading has failed or the primitive [buffer] passed is null + * @throws IOException if the library has failed to read the file into the [out] buffer + * or if the java primitive byte array [buffer] is inaccessible + */ + public native int readIntoArray(byte[] buffer, int offset, int length) throws IOException; + + /** + * Reads the vorbis file into a direct {@link java.nio.ByteBuffer}, starting from offset [0] till the buffer end on the output buffer. + * + * @param out a reference to the output direct buffer + * @throws IOException if a premature EOF is encountered before reaching the end of the buffer + * or if the library has failed to read the file into the [out] buffer + */ + public native void readIntoBuffer(ByteBuffer out) throws IOException; - public native void readFully(ByteBuffer out) throws IOException; + /** + * Clears the native resources and destroys the buffer {@link NativeVorbisFile#ovf} reference. + */ + public native void clearResources(); - public native void close(); + /** + * Prepares the java fields for the native environment. + */ + private static native void preInit(); - public static native void nativeInit(); + /** + * Initializes an ogg vorbis native file from a file descriptor [fd] of an already opened file. + * + * @param fd an integer representing the file descriptor + * @param offset an integer representing the start of the buffer + * @param length an integer representing the length of the buffer + * @throws IOException in cases of a failure to initialize the vorbis file + */ + private native void init(int fd, long offset, long length) throws IOException; } diff --git a/jme3-android/src/main/java/com/jme3/audio/plugins/NativeVorbisLoader.java b/jme3-android/src/main/java/com/jme3/audio/plugins/NativeVorbisLoader.java index 3093b0d4b2..63517cd3d8 100644 --- a/jme3-android/src/main/java/com/jme3/audio/plugins/NativeVorbisLoader.java +++ b/jme3-android/src/main/java/com/jme3/audio/plugins/NativeVorbisLoader.java @@ -1,3 +1,34 @@ +/* + * Copyright (c) 2009-2023 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package com.jme3.audio.plugins; import android.content.res.AssetFileDescriptor; @@ -33,12 +64,12 @@ public int read() throws IOException { @Override public int read(byte[] buf) throws IOException { - return file.read(buf, 0, buf.length); + return file.readIntoArray(buf, 0, buf.length); } @Override public int read(byte[] buf, int off, int len) throws IOException { - return file.read(buf, off, len); + return file.readIntoArray(buf, off, len); } @Override @@ -57,7 +88,7 @@ public void setTime(float time) { @Override public void close() throws IOException { - file.close(); + file.clearResources(); afd.close(); } } @@ -71,14 +102,14 @@ private static AudioBuffer loadBuffer(AssetInfo assetInfo) throws IOException { int fd = afd.getParcelFileDescriptor().getFd(); file = new NativeVorbisFile(fd, afd.getStartOffset(), afd.getLength()); ByteBuffer data = BufferUtils.createByteBuffer(file.totalBytes); - file.readFully(data); + file.readIntoBuffer(data); AudioBuffer ab = new AudioBuffer(); ab.setupFormat(file.channels, 16, file.sampleRate); ab.updateData(data); return ab; } finally { if (file != null) { - file.close(); + file.clearResources(); } if (afd != null) { afd.close(); @@ -107,7 +138,7 @@ private static AudioStream loadStream(AssetInfo assetInfo) throws IOException { } finally { if (!success) { if (file != null) { - file.close(); + file.clearResources(); } if (afd != null) { afd.close();