Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Java Development

Reply
New Developer
Marek_
Posts: 24
Registered: ‎07-20-2009
My Device: Not Specified
Accepted Solution

Player custom DataSource streaming without RTSP possible?

Dear Folks,

did anybody SUCCEED with Manager.createPlayer(DataSource source)
with custom DataSource with real audio STREAMING?
I mean without using the "rtsp://" locator, just feeding the player with your data buffer, which is growing...

The RIM example is downloading the complete file first which is nothing new when compared to the default behaviour of Player (read complete datafile before playing; I understand that this might fit into J2ME standard, but then such methods doesn't make sense :smileysad:

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), the it starts playing (plays the part that he was able to buffer at the beginning) but ends up with error code 5 which "Unspecified: some error occured which does not fit into any other category."

Please use plain text.
Developer
Developer
rab
Posts: 283
Registered: ‎07-22-2008
My Device: Not Specified

Re: Player custom DataSource streaming without RTSP possible?

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

Please use plain text.
Developer
Posts: 1,474
Registered: ‎04-14-2009
My Device: Not Specified

Re: Player custom DataSource streaming without RTSP possible?

[ Edited ]
Make sure you are sending the 6-byte AMR stream header ("#!AMR\n") before the rest of the stream (consisting of AMR frames).
Message Edited by klyubin on 08-18-2009 06:45 PM
Please use plain text.
New Developer
Marek_
Posts: 24
Registered: ‎07-20-2009
My Device: Not Specified

Re: Player custom DataSource streaming without RTSP possible?

@klyubin - Yes, first 6 bytes of the stream is the AMR header
@rab
I'm testing on BB9000 and debugging shows following:

SMP:smileyfrustrated:treaming session aquired id=2313
MN: init0(2000000)=0
MN: load 1
player update com.rim.loading eventData null
MN: getPlayableStreams0(2000000)=1
MN: getLength0(2000000)=-1
MN: getPlayableStreams0(2000000)=1
MN: isSeekable0(2000000)=0
MN: play0(2000000) is audio, NO check for active pause
MN: play0(2000000)=0

update com.rim.playableStreams eventData 1
update started eventData 0
update bufferingStopped eventData 0
update error eventData 5
update stopped eventData 2940000
Streaming done reason=1 prev-state=300

While at the time of buffering I can see that the method
read(byte[] b, int off, int len) of my SourceStream is beeing called (starting with length=58000 down to 4702, where I was still responding with the maximum I had at the time in the stream which was length of 2538),
after MN: play0(2000000) is audio, NO check for active pause there were NO calls for additional data (although the buffer was growing in the meantime)
Please use plain text.
Developer
Posts: 1,474
Registered: ‎04-14-2009
My Device: Not Specified

Re: Player custom DataSource streaming without RTSP possible?

Are you sure you're returning your stream correctly via the read() method? May be you could post the code...
Please use plain text.
New Developer
Marek_
Posts: 24
Registered: ‎07-20-2009
My Device: Not Specified

Re: Player custom DataSource streaming without RTSP possible?

[ Edited ]

Well, I'm not sure :smileyhappy: 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); 

Update: now the player loops the first buffered fragrment, so there's no error 5 but there are also no additional requests for new data and the player still loops the short first fragment.. :smileysad:
Message Edited by Marek_ on 08-19-2009 11:01 AM
Please use plain text.
Developer
Posts: 1,474
Registered: ‎04-14-2009
My Device: Not Specified

Re: Player custom DataSource streaming without RTSP possible?

[ Edited ]

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).

Message Edited by klyubin on 08-19-2009 08:37 PM
Please use plain text.
New Developer
Marek_
Posts: 24
Registered: ‎07-20-2009
My Device: Not Specified

Re: Player custom DataSource streaming without RTSP possible?

Klyubin, you were right, thank you very much!
Since I was only able to find this streaming example http://tinyurl.com/34w73t where the stream is opened from a file, I rather did the rest by myself according to your suggestions. Now it's working like expected.
Please use plain text.
Developer
naveen4nkp
Posts: 41
Registered: ‎04-10-2009
My Device: Not Specified

Re: Player custom DataSource streaming without RTSP possible?

[ Edited ]

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  ,

Message Edited by naveen4nkp on 09-01-2009 07:55 AM
Please use plain text.
New Developer
Marek_
Posts: 24
Registered: ‎07-20-2009
My Device: Not Specified

Re: Player custom DataSource streaming without RTSP possible?

Hi there,
please read the whole thread - included the klyubin correction for the read method where I was not reacting according to read contract.
If you increase your buffer to some bigger amout(cca. 5kb; ~3sec) the player shuld be able to play the block without additional data, if it can't, check whether your amr data are valid (make sure you have the 6B AMR header at the beginning of the stream)
Please use plain text.