08-17-2009 12:41 PM
Solved! Go to Solution.
08-17-2009 05:10 PM
Yes, the custom Datasource works fine. But it is not as RTSP.
The idea there is to invoke the player and feed to it the data as it becomes available. So it is a simplified version of streaming. The player will start playing before receiving the entire file.
You may get error 5 if the download rate cannot keep up with the player. ( one of the causes).
What device are trying this on?
Rab
08-18-2009 01:44 PM - edited 08-18-2009 01:45 PM
08-18-2009 05:51 PM
08-18-2009 06:03 PM
08-19-2009 02:45 AM - edited 08-19-2009 05:01 AM
Well, I'm not sure
but I can hear the first few seconds of audio that the player was trying to cache at the beginning, however, here's my code:
public class PlayerStreamDataSource extends DataSource {
public final static String CONTENT_TYPE = "audio/amr";
private final static byte[] AMR_HEADER = {(byte) 0x23, (byte) 0x21, (byte) 0x41,
(byte) 0x4d, (byte) 0x52,(byte) 0x0a};
private NoCopyByteArrayOutputStream baos;
private PlayerSourceStream playerSourceStream;
private volatile int totalRead;
private volatile boolean _stop = false;
public PlayerStreamDataSource(String locator) {
super(locator);
this.baos = new NoCopyByteArrayOutputStream(30000);
this.playerSourceStream = new PlayerSourceStream(CONTENT_TYPE, baos);
try {
baos.write(AMR_HEADER);
} catch (IOException e) {
System.out.println(e);
}
}
public void connect() throws IOException {
// TODO Auto-generated method stub
}
public void disconnect() {
try {
stop();
baos.close();
playerSourceStream = null;
} catch (IOException e) {
System.out.println(e);
}
}
public SourceStream[] getStreams() {
return new SourceStream[] {
playerSourceStream
};
}
public void start() throws IOException {
// TODO Auto-generated method stub
}
public void stop() throws IOException {
_stop = true;
}
public String getContentType() {
return playerSourceStream.getContentDescriptor().getContentType();
}
public Control getControl(String controlType) {
// TODO Auto-generated method stub
return null;
}
public Control[] getControls() {
// TODO Auto-generated method stub
return null;
}
public NoCopyByteArrayOutputStream getBaos() {
return baos;
}
}
public class PlayerSourceStream implements SourceStream {
private ContentDescriptor _contentDescriptor;
private long currentPosition;
private NoCopyByteArrayOutputStream stream;
public PlayerSourceStream(String contentType, NoCopyByteArrayOutputStream stream) {
_contentDescriptor = new ContentDescriptor(contentType);
this.stream = stream;
currentPosition = 0;
}
public ContentDescriptor getContentDescriptor() {
return _contentDescriptor;
}
public long getContentLength() {
return -1;
}
public int getSeekType() {
return SEEKABLE_TO_START;
}
public int getTransferSize() {
return 16;
}
public int read(byte[] b, int off, int len) throws IOException {
if ((currentPosition + len) > stream.size()) {
int currentSize = stream.size();
System.arraycopy(stream.getByteArray(), (int) currentPosition, b, off, currentSize);
System.out.println("Stream READ request beyond buffer size: "
+ Long.toString(currentPosition) + " len: " + Integer.toString(len) + " returning " + Integer.toString(currentSize));
return currentSize;
} else {
System.arraycopy(stream.getByteArray(), (int) currentPosition, b, off, len);
return len;
}
}
public long seek(long where) throws IOException {
if (where <= 0) this.currentPosition = 0;
else if (where < stream.size()) this.currentPosition = where;
else {
System.out.println(Seek request beyond buffer size: " + Long.toString(where));
}
return this.currentPosition;
}
public long tell() {
return currentPosition;
}
public Control getControl(String controlType) {
// TODO Auto-generated method stub
return null;
}
public Control[] getControls() {
// TODO Auto-generated method stub
return null;
}
}
In another thread I'm receiving the audio data and writing them into the NoCopyByteArrayOutputStream so it's constantly growing.
AmrPlayer
....
playerStreamDataSource = new PlayerStreamDataSource("audio/amr"); // no idea what locator should I use here
player = Manager.createPlayer(playerStreamDataSource);
08-19-2009 03:34 PM - edited 08-19-2009 03:37 PM
Looks like you aren't complying with the contract of the SourceStream.read method. Firstly, if currentPosition + len > stream.size(), then you're returning stream.size() bytes rather than stream.size() - currentPosition bytes. Secondly, if currentPosition + len <= stream.size(), you're returning the right bytes for the first time, but then you don't appear to be updating the currentPosition variable -- so, if the condition is still true on the next read, you're returning the same frames as last time causing the user to hear a loop.
Here's how the read method should look like (minus the blocking part when no data is available, and minus the -1 or EOFException when the SourceStream is closed/stopped) -- I haven't tried compiling or running it though:
public int read(byte[] b, int off, int len) throws IOException {
if (len < 1) {
return 0;
}
final int streamSize = stream.size();
final int currentPosition = (int) this.currentPosition;
final int bytesToReturn = Math.min(streamSize - currentPosition, len);
if (bytesToReturn < 1) {
// TODO: Need to block here on the stream until some bytes are available
return 0;
}
System.arraycopy(stream.getByteArray(), currentPosition, b, off, bytesToReturn);currentPosition += bytesToReturn;
return bytesToReturn;
}
P.S. Some RIM examples (don't remember which ones) have a shared stream into which one threads writes some data and another thread reads data from. This could be another (simpler) solution to your problem, because your read will be a one-liner: return sharedStream.read(b, off, len).
08-20-2009 09:46 AM
09-01-2009 05:53 AM - edited 09-01-2009 07:55 AM
Hi marek ,
I am facing a problem, when i am trying to iplement the above code in my application, It not plying any thing,
When I try to play a stream of audio (audio/amr) I see that the player is trying to cache the data first (calling read() with length starting with 58000 down to my actual buffer size), but nothing paying on device . I thing may be i am not writing the recived data into the NoCopyByteArrayOutputStream correctly . Can you help me
Thanks ,
09-01-2009 08:35 AM