I would like to repeatedly capture snippets of audio on a Nokia mobile phone with a Java Midlet. My current experience is that using the code in Sun's documentation (see: http://java.sun.com/javame/reference/apis/jsr135/javax/microedition/media/control/RecordControl.html) and wrapping this in a "while(true)" loop works, but the application slowly consumes all the memory on the phone and the program eventually throws an exception and fails to initiate further recordings.
The consumed memory isn't Java heap memory---my example program (below) shows that Java memory stays roughly static at around 185,000 bytes---but there is some kind of memory leak in the underlying supporting library provided by Nokia; I believe the memory leak occurs because if you try and start another (non-Java) application (e.g. web browser) after running the Java application for a while, the phone kills that application with a warning about lack of memory.
I've tried several different approaches from that taken by Sun's canonical example in the documentation (initialize everything each time round the loop, initialize as much as possible only once, call as many of the deallocate-style functions which shouldn't be strictly necessary etc.). None appear to be successful. Below is a simple example program which I believe should work, but crashes after running for 15 minutes or so on both the N80 (despite a firmware update) and N95. Other forums report this problem too, but the solutions presented there do not appear to work (for example, see: http://discussion.forum.nokia.com/forum/showthread.php?t=129876).
import javax.microedition.media.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.io.*;
public class Standalone extends MIDlet {
protected void startApp() {
final Form form = new Form("Test audio recording");
final StringItem status = new StringItem("Status","");
form.append(status);
final Command exit = new Command("Exit", Command.EXIT, 1);
form.addCommand(exit);
form.setCommandListener(new CommandListener() {
public void commandAction(Command cmd, Displayable disp) {
if (cmd == exit) {
destroyApp(false);
notifyDestroyed();
}
}
});
Thread t = new Thread(){
public void run() {
int counter = 0;
while(true) {
//Code cut 'n' paste from Sun JSR135 javadocs for RecordControl:
try {
Player p = Manager.createPlayer("capture://audio");
p.realize();
RecordControl rc = (RecordControl)p.getControl("RecordControl");
ByteArrayOutputStream output = new ByteArrayOutputStream();
rc.setRecordStream(output);
rc.startRecord();
p.start();
Thread.currentThread().sleep(5000);
rc.commit();
p.close();
} catch (Exception e) {
status.setText("completed "+counter+
" T="+Runtime.getRuntime().totalMemory()+
" F="+Runtime.getRuntime().freeMemory()+
": Error: "+e);
break;
}
counter++;
status.setText("completed "+counter+
" T="+Runtime.getRuntime().totalMemory()+
" F="+Runtime.getRuntime().freeMemory());
System.gc(); //One forum post suggests this, but doesn't help
this.yield();
}
}
};
t.start();
final Display display = Display.getDisplay(this);
display.setCurrent(form);
}
protected void pauseApp() {}
protected void destroyApp(boolean bool) {}
}