I have a dummy Stream<int> called intialStream and I am mapping it into another stream, called mappedStream. which is supposed to be a new stream as I quote from the documentation of the map method:
Creates a new stream that converts each element of this stream to a
new value using the convert function, and emits the result.
void main() {
Stream<int> initialStream = Stream<int>.value(0);//using broadcast stream instead, makes the code work, as if dart considers the mapped stream to be the same stream as this one when I am using non-broadcast streams !
initialStream.listen(print);
var mappedStream = initialStream.map((nb) => nb + 1);
print(initialStream == mappedStream); // prints false !
mappedStream.listen(print);//error here
}
The problem is that when I try to listen to the mapped stream, I get an error:
Bad state: Stream has already been listened to.
Isn't this supposed to be a new stream and thus I can listen to it separately?
Yes, you do create a new stream when you use map() method, but the new stream also listens on the original stream. So, you cannot listen on the new stream that is created using the methods (map(), where(), expand()...) after adding a subscription to the original stream which is single-subscription.
It's not explicitly stated in docs, but check out the following lines that you might get a general idea:
Methods that modify a stream
The following methods on Stream return a new stream based on the
original stream. Each one waits until someone listens on the new
stream before listening on the original:
Stream<R> cast<R>();
Stream<S> expand<S>(Iterable<S> Function(T element) convert);
Stream<S> map<S>(S Function(T event) convert);
Stream<T> skip(int count);
Stream<T> skipWhile(bool Function(T element) test);
Stream<T> take(int count);
Stream<T> takeWhile(bool Function(T element) test);
Stream<T> where(bool Function(T event) test);
Here, you can say that the new stream will listen on the original one once a subscription is added. Therefore, it will throw error if the original stream is single-subscription and it already has a listener.
Related
I'm receiving a PCM buffer from websocket onmessage method as result
console.log('cleblanc length of TTS data ' + result.byteLength);
const buff = new Uint16Array(result);
console.log('cleblanc TTS data ' + buff);
RNTtsPlayer.playTts(buff);
and my native method
#ReactMethod
public void playTts(ReadableArray readableArray)
It's causing Malformed calls from JS: field sizes are different
I'd like to pass the data as a ReadableArray, but when I try using ReadableMap and passing result directly it results in the Java layer receiving an empty map. Should I try converting it to a String or is there a way to make this work.
So I wound up converting the ReadableArray to a base64 string like this;
new Buffer(result).toString('base64')
And then simply decoding it in the Java like this;
samples[producerIdx] = Base64.decode(data, Base64.DEFAULT);
producerIdx++;
Where samples is a new byte[32][];
My application subscribes to an Observable<Timestamped<byte[]>> of data packets arriving in sequence, and assembles them into larger frames. It must examine each packet to find the "Start of Frame" header and do some minor processing to assemble the packets into a valid frame.
How can I create a new Observable<Frame> that will emit these completed frames to a Subscriber?
Update: the suggested answer doesn't want to work for me. Some details:
My source Observable emits Timestamped<byte[]> packets.
Desired Output is an Observable of DataFrame objects, each including the data from several packets along with some other fields.
I have a class FrameAssembler with a method DataFrame receivePacket( Timestamped<byte[]> packet ). It returns null until it has assembled a frame, which it then returns and gets ready for the next one.
I can't create the output Observable. I'm trying this
Observable<DataFrame> source = Observable
.just( new Timestamped<byte[]>(100, new byte[10]) ) // sample packet
.scan( new FrameAssembler(), (acc, packet) -> acc.receivePacket( packet ))
.filter( frame -> frame != null )
but the lambda is underlined, with the message "Bad return type in lambda expression: DataFrame cannot be converted to TestScan.FrameAssembler".
I'm thoroughly stumped by this. What is acc and what's it doing there? Why does it want to convert the DataFrame returned by receivePacket into FrameAssembler? And why is new FrameAssembler() used as the first argument to scan()?
You probably want to use the 2-parameter scan operator:
class ByteAccumulator {
private byte[] buffer = ...
public byte[] receivePacket(byte[] receivedPacket) {
// add the received packet to the buffer
if(containsFullFrame(buffer)) {
return extractFrameAndTrimBuffer();
} else {
return null;
}
}
}
Observable<byte[]> source = ...
source.scan(new ByteAccumulator(), ByteAccumulator::receivePacket)
.filter(frame -> frame != null)
...
Edit: You need an intermediate class to adapt your FrameAssembler to what scan expects:
public FrameScanner {
private final FrameAssembler assembler;
private final DataFrame frame;
public FrameScanner() {this(new FrameAssembler(), null);}
public FrameScanner(FrameAssembler assembler,DataFrame frame) {
this.frame=frame; this.assembler=assembler;
}
public getFrame() {return frame;}
public FrameScanner scan(Timestamped<byte[]> nextBytes) {
return new FrameScanner(assembler, assembler.receivePacker(nextBytes));
}
}
Now you should be able to use it like this:
.scan(new FrameScanner(), FrameScanner::scan)
.map(FrameScanner::getFrame)
.filter(Objects::nonNull)
Hmm... now that I think about it, instead of the abofethis might also work:
FrameAssembler assembler=new FrameAssembler();
...
.scan((DataFrame)null, (ignore, packet) -> assembler.receivePacket( packet))
.filter(Objects::nonNull)
I couldn't get the proposed solution using the scan() operator to work. I believe the problem was the null being returned until a complete set of packets was received. Observable operator chains don't seem to like nulls.
How I solved it:
In the onNext() handler of the data packet Observable subscription:
Thread.currentThread().setPriority( DATA_RX_PRIORITY );
packetArrayList = DataOps.addPacket( packetArrayList, dataPacket );
if( packetArrayList != null ) { // we have a new complete packet buffer
DataOps.DataFrame frameReturned = DataOps.pBuf2dFrame( packetArrayList );
frameRelayer.onNext( frameReturned ); // send the new frame to the BehaviorSubject
}
The addPacket() routine adds each received packet to an ArrayList, but returns null except when a complete Frame's packets have been accumulated, when it returns the filled ArrayList.
When a non-null ArrayList is received, the pBuf2dFrame() method parses the packets and assembles them into a new DataFrame object.
Then comes the trick that converts the Observable of packets into an Observable of DataFrames: frameRelayer is a BehaviorSubject (an RxJava object that can function as both an Observable and a Subscriber). All you have to do is call its onNext() method with the new DataFrame to have it passed on to any Subscribers to frameRelayer.
I'm working on an app that records video in background and sends it to server in parts by reading bytes and storing them in byte array. For now algorithm is pretty simple:
start recording;
reading part of video file to byte array;
send byte array via POST (with help of retrofit).
Problem occurs if connection somehow interrupts and last part isn't sent. Server just can't make readable video file as moov atom would be written only after recording stops. My question - is it possible some how to make complete video files from byte array parts or any other way? I can change video codec if it would solve the problem.
p.s. I can only send data via POST.
p.p.s I can't change something on server side including streaming video directly to server.
SOLUTION
I decided to record small chunks of video in recursive way. Next solution is suitable for first version of Camera API. If you're using Camera2 or something else - you can try to use same algorithm.
In service class that records video make sure that mediarecorder is configured next way:
mediaRecorder.setMaxDuration(10000);
//or
mMediaRecorder.setMaxFileSize(10000);
Then you need to implement setOnInfoListener interface next way:
mediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
#Override
public void onInfo(MediaRecorder mr, int what, int extra) {
if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
//Use next condition if you decided to use max file size
//if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED)
stopRecording();
setRecordingStatus(false);
startRecording(surfaceHolder);
}
}
});
Don't forget to pass surfaceHolder instance for next iteration otherwise you can get "Application lost surface" error.
Next thing you need to do is declare FileObserver in onCreate method:
FileObserver fileObserver = new FileObserver(pathToFolder, FileObserver.CLOSE_WRITE) {
//FileObserver.CLOSE_WRITE mask means that this observer would be triggered when it receive end of writing to file system event
#Override
public void onEvent(int event, String path) {
//here path is name of file (with extension) but not the full path to file
if (event == FileObserver.CLOSE_WRITE && path.endsWith(".mp4")) {
String name = String.valueOf(Long.parseLong(path.substring(0, path.length() - 4)) / 1000);
sendNewVideo(pathToFolder + "/" + path, name);
}
}
};
In onStartCommand method:
fileObserver.startWatching();
I'm communication with a server through a tcp socket connection, i'm able to read lines that ends with \n fine, however when the line is not terminated (ends in \n) i'm not able to read it. I tried the following but it didn't work and caused my app to freeze at startup:
private Socket socket;
private BufferedReader input;
public boolean isConnected;
#Override
public void onCreate()
{
try
{
socket = new Socket ("server.ip.add.ress", 23456);
input = new BufferedReader (new InputStreamReader (socket.getInputStream());
handshake();
isConnected = true;
}
catch // Handle IOException and UnknownHostException
}
// custom runnable to read availabe input from the server
private class MyRunnable implements Runnable
{
private volativle String value;
public String getValue()
{
return value;
}
#Override
public void run()
{
int count;
char[] buffer = new char[10]; // expected message 'username: '
try
{
count = input.read (buffer, 0, 10);
if (count > 0) value = new String (buffer);
}
catch // IOException
}
}
// when connection is established with server expect 'username: ' from
// the server and send the user name back to it
public void handshake()
{
MyRunnable runnable = new MyRunnable();
try
{
Thread thread = new Thread (runnable);
thread.start();
thread.join();
String greeting = runnable.getValue();
if (greeting.equals ("username: ")) // Send username back
}
catch // InterruptedException
}
why is it hanging? and how can i read a non terminated line?
Edit:
To clarify: The server sends the greeting message username: immediately after the connection is established with a client, the client wait for the greeting and send back it's username when received (that's what handshake() does), if no handshake the client disconnects otherwise it start listening for incoming messages. Because i need to know if handshake is complete before starting the listener i had to use Thread.join().
The problem: Thanks for the comments and answers below, it turned out that BufferedReader.read() blocks the thread and waits until something is sent from the server and if nothing is being sent it causes the app to hang, Therefor there's no way to find out if the line has ended.
The solution: In my specific situation i just wanted to know if a specific message is sent "username: " so i used read (buffer, 0, 10) to read exactly 10 characters (the length of "username: "), and because it blocks if nothing is sent i used Thread.join (1000) which waits only one second and then if nothing received i disconnect the client.
Why is it hanging?
This is what it is suppose to be. It will block the thread if no data is available to read. This is also why you want to put it in a background thread.
Can it not just return if nothing is available?
What you are looking for is ready(), which will tell you whether there is available data or not.
Indicates whether this reader is ready to be read without blocking.
Returns
true if this reader will not block when read is called, false if unknown or blocking will occur.
But you should be very careful when using this function. Because networking is a lot about timing. The fact that you don't have any data to read at this second doesn't necessary mean that it won't be any data in the next second.
So a better design of the server should be more or less as the following:
If the username is found, return the username
If the username is not found, return an error message to let the client side know that the username is not found
There's no need for the thread. Your goal is to wait until you've read what you've been waiting for. Why not just let read() perform the wait for you?
What you're struggling with is the classic problem of TCP communication: "when do I know that I've got everything the server sent?"
In your case, you're expecting to read bytes until the collection of bytes ends with "username: ". So, change your algorithm to perform 1 byte reads (filling a buffer as you go) until that buffer ends with "username: ".
You can make a more complicated algorithm -- which would be more efficient -- that would attempt to read multiple bytes at a time and append them to a buffer -- performing your check each time. But either strategy is logically equivalent.
I also recommend just using the InputStreamReader. It has various read() methods. I am a bit suspicious about the BufferedInputReader, especially when dealing with data that isn't newline terminated. I'm probably just paranoid. I've just never used it when writing TCP client/server programs, so I'm not sure.
I am writing an android app that recieves data over bluetooth. The bytes comming in can be of any size example: 00023>024935928598235>9284>
As you can see each set is seperated by ">". The data comes in extremely fast. I would like some ideas for an implementation. See my problem is that I need to read the data into a byte array that can and then convert it to a string and split them according to the delimeter of ">".
so in the above example:
00023
024935928598235
9284
If i set byte[] data = new byte[8] then when reading the incomming data it might get 00023>02 which is not what i want. I'm not sure how to implement something like this. Any ideas?
Here's one approach. You'll have to implement the readDataFromBluetooth() and somehow set dataAvailable, but this should get you on the right track.
byte[] data = new byte[1024];
List<String> chunks = new LinkedList<String>();
StringBuilder chunk = new StringBuilder();
while (dataAvailable) {
data = readDataFromBluetooth();
for (byte b : data) {
if (b == '<') {
chunks.add(chunk.toString());
chunk.setLength(0);
} else {
chunk.append(b);
}
}
}
if (chunk.length() > 0)
chunks.add(chunk.toString());
I would recommend using a buffered stream, but maybe a bit bigger that 8 bytes, as you suggest, and the read one and one character from the beginning of the stream, accumulating the string. When you encounter a ">", send the value you have accumulated off to a queue for a background thread processing. Use standard producer/consumer implementation techniques (e.g. the Monitor pattern) to communicate via the queue.