/*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* 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 version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.mmedia;
import javax.microedition.media.*;
import javax.microedition.media.protocol.SourceStream;
import java.io.IOException;
/**
* The thread that's downloads media data
*
*/
class MediaDownload {
/**
* the stream instance
*/
private SourceStream stream;
private long contLength = -1;
private int packetSize = 0;
private int javaBufSize = 0;
private byte[] buffer = null;
private boolean eom = false;
private int hNative;
private boolean needMoreData = false;
private Thread downloadThread = null;
private boolean stopDownloadFlag = false;
// get java buffer size to determine media format
static native int nGetJavaBufferSize(int handle);
// get first packet size to determine media format
static native int nGetFirstPacketSize(int handle);
// buffering media data
static native int nBuffering(int handle, byte[] buffer, int offset, int size);
// ask Native Player if it needs more data immediatelly
static native boolean nNeedMoreDataImmediatelly(int hNative);
// Provide whole media content size, if known
static native void nSetWholeContentSize(int hNative, long contentSize);
/**
* The constructor
*
* @param stream the instance of stream.
*/
MediaDownload(int hNative, SourceStream stream) {
this.hNative = hNative;
this.stream = stream;
eom = false;
contLength = -1;
}
void deallocate() {
stopDownload();
eom = false;
contLength = -1;
buffer = null;
javaBufSize = 0;
packetSize = 0;
}
/**
*
*/
void fgDownload() throws IOException, MediaException {
download(false);
}
/**
*
*/
void bgDownload() {
if (!eom) {
downloadThread = new Thread() {
public void run() {
try {
download(true);
} catch (Exception e) {
}
}
};
downloadThread.start();
}
}
synchronized void continueDownload() {
needMoreData = true;
notifyAll();
}
void stopDownload() {
if (downloadThread != null && downloadThread.isAlive()) {
stopDownloadFlag = true;
try {
downloadThread.join();
} catch(InterruptedException ex) {;}
stopDownloadFlag = false;
downloadThread = null;
needMoreData = false;
}
}
private synchronized void download( boolean inBackground ) throws MediaException, IOException {
int roffset = 0;
int woffset = 0;
if (contLength == -1) {
contLength = stream.getContentLength();
if (contLength > 0) {
nSetWholeContentSize(hNative, contLength);
}
}
int newJavaBufSize = nGetJavaBufferSize(hNative);
packetSize = nGetFirstPacketSize(hNative);
if(packetSize > 0 && !eom) {
if (newJavaBufSize < packetSize) {
newJavaBufSize = packetSize;
}
if (buffer == null || newJavaBufSize > buffer.length) {
do {
try {
buffer = new byte[ newJavaBufSize ];
} catch(OutOfMemoryError er) {
if (newJavaBufSize == packetSize) {
throw new MediaException("Not enough memory");
} else {
newJavaBufSize = newJavaBufSize/2;
if (newJavaBufSize < packetSize) {
newJavaBufSize = packetSize;
}
}
};
}while (buffer == null);
javaBufSize = newJavaBufSize;
}
if (inBackground) {
woffset = bgDownloadAndWait(woffset);
}
if (!stopDownloadFlag) {
do {
int num_read = woffset - roffset;
int ret;
if (num_read > packetSize) {
num_read = packetSize;
}
if (num_read < packetSize && !eom) {
if ((roffset + packetSize) > javaBufSize) {
woffset = moveBuff(roffset, woffset);
roffset = 0;
}
do {
ret = stream.read(buffer, woffset, packetSize-num_read);
if (ret == -1) {
eom = true;
break;
}
num_read += ret;
woffset += ret;
}while(num_read<packetSize);
}
packetSize = nBuffering(hNative, buffer, roffset, num_read);
roffset += num_read;
if (packetSize == -1) {
packetSize = 0;
needMoreData = false;
throw new MediaException("Error data buffering or encoding");
} else if (packetSize > javaBufSize){
if ((woffset - roffset)==0) {
javaBufSize = packetSize;
buffer = new byte[ javaBufSize ];
} else {
javaBufSize = packetSize;
byte[] b = new byte[ javaBufSize ];
for (int i=0, j=roffset; j<woffset; i++, j++) {
b[i] = buffer[j];
}
buffer = b;
woffset -= roffset;
roffset = 0;
}
}
if (roffset == woffset) {
roffset = 0;
woffset = 0;
if (eom) {
break;
}
}
needMoreData = nNeedMoreDataImmediatelly(hNative);
if (inBackground && !needMoreData) {
woffset = moveBuff(roffset, woffset);
roffset = 0;
woffset = bgDownloadAndWait(woffset);
}
}while (needMoreData && !stopDownloadFlag);
}
if (eom) {
packetSize = nBuffering(hNative, null, 0, 0);
needMoreData = false;
}
buffer = null;
}
}
private int moveBuff(int roffset, int woffset) {
for (int i=0, j=roffset; j<woffset; i++, j++) {
buffer[i] = buffer[j];
}
return woffset-roffset;
}
private int bgDownloadAndWait(int offset) throws IOException {
while (!needMoreData && !stopDownloadFlag) {
if (offset<javaBufSize && !eom) {
int num_read = packetSize;
if (offset + num_read >javaBufSize) {
num_read = javaBufSize - offset;
}
int ret = stream.read(buffer, offset, num_read);
if (ret == -1) {
eom = true;
} else {
offset += ret;
}
} else {
try {
wait(500);
} catch (InterruptedException e) {
}
}
}
return offset;
}
}