|
@@ -1,5 +1,6 @@
|
|
|
#include <unistd.h>
|
|
|
#include <stdlib.h>
|
|
|
+#include <errno.h>
|
|
|
#include "Tremor/ivorbisfile.h"
|
|
|
|
|
|
#include "com_jme3_audio_plugins_NativeVorbisFile.h"
|
|
@@ -18,40 +19,105 @@ typedef struct
|
|
|
{
|
|
|
JNIEnv* env;
|
|
|
int fd;
|
|
|
+ int start;
|
|
|
+ int end;
|
|
|
+ int current;
|
|
|
}
|
|
|
FileDescWrapper;
|
|
|
|
|
|
+// size_t read (int fd, void *buf, size_t nbytes)
|
|
|
static size_t FileDesc_read(void *ptr, size_t size, size_t nmemb, void *datasource)
|
|
|
{
|
|
|
FileDescWrapper* wrapper = (FileDescWrapper*)datasource;
|
|
|
- size_t totalRead = read(wrapper->fd, ptr, size * nmemb);
|
|
|
|
|
|
- LOGI("read(%zu) = %zu", size * nmemb, totalRead);
|
|
|
+ int req_size = size * nmemb;
|
|
|
+ int to_read = req_size;
|
|
|
|
|
|
- return totalRead;
|
|
|
+ if (wrapper->end - wrapper->current > req_size)
|
|
|
+ {
|
|
|
+ to_read = wrapper->end - wrapper->current;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (to_read <= 0)
|
|
|
+ {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ size_t total_read = read(wrapper->fd, ptr, to_read);
|
|
|
+
|
|
|
+ if (total_read > 0)
|
|
|
+ {
|
|
|
+ wrapper->current += total_read;
|
|
|
+ }
|
|
|
+
|
|
|
+ LOGI("FD read(%d) = %zu", to_read, total_read);
|
|
|
+
|
|
|
+ return total_read;
|
|
|
}
|
|
|
|
|
|
// off64_t lseek64(int fd, off64_t offset, int whence);
|
|
|
static int FileDesc_seek(void *datasource, ogg_int64_t offset, int whence)
|
|
|
{
|
|
|
FileDescWrapper* wrapper = (FileDescWrapper*)datasource;
|
|
|
- int result = lseek64(wrapper->fd, offset, whence);
|
|
|
-
|
|
|
- char* whenceStr;
|
|
|
- switch (whence) {
|
|
|
- case SEEK_CUR: whenceStr = "SEEK_CUR"; break;
|
|
|
- case SEEK_END: whenceStr = "SEEK_END"; break;
|
|
|
- case SEEK_SET: whenceStr = "SEEK_SET"; break;
|
|
|
- default: whenceStr = "unknown"; break;
|
|
|
+
|
|
|
+ int actual_offset;
|
|
|
+
|
|
|
+ switch (whence)
|
|
|
+ {
|
|
|
+ case SEEK_SET:
|
|
|
+ // set the offset relative to start location.
|
|
|
+ actual_offset = wrapper->start + offset;
|
|
|
+ break;
|
|
|
+ case SEEK_END:
|
|
|
+ // seek from the end of the file.
|
|
|
+ // offset needs to be negative in this case.
|
|
|
+ actual_offset = wrapper->end + offset;
|
|
|
+ break;
|
|
|
+ case SEEK_CUR:
|
|
|
+ // seek relative to current position.
|
|
|
+ actual_offset = wrapper->current + offset;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ // invalid whence.
|
|
|
+ errno = EINVAL;
|
|
|
+ return (off_t)-1;
|
|
|
}
|
|
|
- LOGI("seek(%lld, %s) = %d", offset, whenceStr, result);
|
|
|
+
|
|
|
+ if (actual_offset < wrapper->start ||
|
|
|
+ actual_offset > wrapper->end)
|
|
|
+ {
|
|
|
+ // actual offset should be within our acceptable range.
|
|
|
+ errno = EINVAL;
|
|
|
+ return (off_t)-1;
|
|
|
+ }
|
|
|
+
|
|
|
+ int result = lseek64(wrapper->fd, actual_offset, SEEK_SET);
|
|
|
+
|
|
|
+ LOGI("FD seek(%d) = %d", actual_offset, result);
|
|
|
+
|
|
|
+ if (result < 0)
|
|
|
+ {
|
|
|
+ // failed, errno should have been set by lseek.
|
|
|
+ return (off_t)-1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (result != actual_offset)
|
|
|
+ {
|
|
|
+ // did not seek the expected amount. something wrong here.
|
|
|
+ errno = EINVAL;
|
|
|
+ return (off_t)-1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // seek succeeded.
|
|
|
+ // update current position
|
|
|
+ wrapper->current = actual_offset;
|
|
|
}
|
|
|
|
|
|
static int FileDesc_close(void *datasource)
|
|
|
{
|
|
|
FileDescWrapper* wrapper = (FileDescWrapper*)datasource;
|
|
|
|
|
|
- LOGI("close");
|
|
|
+ LOGI("FD close");
|
|
|
|
|
|
return close(wrapper->fd);
|
|
|
}
|
|
@@ -61,7 +127,14 @@ static long FileDesc_tell(void *datasource)
|
|
|
FileDescWrapper* wrapper = (FileDescWrapper*)datasource;
|
|
|
long result = lseek64(wrapper->fd, 0, SEEK_CUR);
|
|
|
|
|
|
- LOGI("tell = %ld", result);
|
|
|
+ LOGI("FD tell = %ld", result);
|
|
|
+
|
|
|
+ if (wrapper->current != result)
|
|
|
+ {
|
|
|
+ // Not sure how to deal with this.
|
|
|
+ LOGI("PROBLEM: stored offset does not match actual: %d != %ld",
|
|
|
+ wrapper->current, result);
|
|
|
+ }
|
|
|
|
|
|
return result;
|
|
|
}
|
|
@@ -102,15 +175,18 @@ JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_nativeInit
|
|
|
}
|
|
|
|
|
|
JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_open
|
|
|
- (JNIEnv *env, jobject nvf, jint fd)
|
|
|
+ (JNIEnv *env, jobject nvf, jint fd, jlong off, jlong len)
|
|
|
{
|
|
|
- LOGI("open: %d", fd)
|
|
|
-
|
|
|
+ LOGI("open: fd = %d, off = %lld, len = %lld", fd, off, len);
|
|
|
+
|
|
|
OggVorbis_File* ovf = (OggVorbis_File*) malloc(sizeof(OggVorbis_File));
|
|
|
|
|
|
FileDescWrapper* wrapper = (FileDescWrapper*) malloc(sizeof(FileDescWrapper));
|
|
|
wrapper->fd = fd;
|
|
|
wrapper->env = env; // NOTE: every java call has to update this
|
|
|
+ wrapper->start = off;
|
|
|
+ wrapper->current = off;
|
|
|
+ wrapper->end = off + len;
|
|
|
|
|
|
int result = ov_open_callbacks((void*)wrapper, ovf, NULL, 0, FileDescCallbacks);
|
|
|
|
|
@@ -148,7 +224,17 @@ JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_open
|
|
|
JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_seekTime
|
|
|
(JNIEnv *env, jobject nvf, jdouble time)
|
|
|
{
|
|
|
+ jobject nvfBuf = (*env)->GetObjectField(env, nvf, nvf_field_ovf);
|
|
|
+ OggVorbis_File* ovf = (OggVorbis_File*) (*env)->GetDirectBufferAddress(env, nvfBuf);
|
|
|
|
|
|
+ int result = ov_time_seek(ovf, time);
|
|
|
+
|
|
|
+ if (result != 0)
|
|
|
+ {
|
|
|
+ char err[512];
|
|
|
+ sprintf(err, "ov_time_seek failed: %d", result);
|
|
|
+ throwIOException(env, err);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
JNIEXPORT jint JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_read
|