Sound output buffer flush - java

I have a jsp that plays wav file through java class in GlassFish. I have used SourceDataline methods:
start();
drain();
close();
The wav file is played properly. For stopping I used:
stop();
flush();
close();
But the play continues with the rest of data inside the output buffer. I went through the documents over www.oracle.com about SourceDataline methods. There it is said that flush() will discard the data inside the SourceDataline object but not the data already inside the output buffer.
Now I want to flush out the data from the output buffer so that there will be no overlapping of sound during the next start.
I searched on JavaScript also but without help.

This is mostly a shot in the dark, but could work: the documentation for TargetDataLine.read says:
Reads audio data from the data line's input buffer. (...) However, if the data line is closed, stopped, drained, or flushed before the requested amount has been read, the method no longer blocks, but returns the number of bytes read thus far.
So, maybe you can try to gain access to the TargetDataLine(s) being used (maybe using Mixer.getTargetLines) and try to act on them too (stopping, flushing etc). I'm not sure, however, if there would be any side-effects of doing that (or even if it's possible at all).
Is there any additional info about your problem you can share? You mentioned jsp, GlassFish and JavaScript, so I'm guessing you're either using an Applet to play the file, or maybe just using Java to mix server-side but sending the resulting file to be handled by the browser. Is any of this correct?

Related

How to set a timeout when reading from a Java RandomAccessFile

I am writing to and reading from a Linux file in java, which in reality is a communication port to a hardware device. To do this I use RandomAccessFile (I'll explain why later) and it works well in most cases. But sometimes a byte is lost and then my routine blocks indefinitely since there is no timeout on the read method.
To give some more details on the file: it is a USB receipt printer that creates a file called /dev/usb/lp0 and though I can use a cups driver to print, I still need the low level communication through this file to query the status of the printer.
The reason I use RandomAccessFile is that I can have the same object for both reading and writing.
I tried to make a version with InputStream and OutputStream instead (since that would allow me to use the available() method to implement my timeout). But when I first open the InputStream and then the OutputStream I get an exception when opening the OutputStream since the file is occupied.
I tried writing with the OutputStream and then closing it before opening the InputStream to read, but then I lose some or all of the reply before it has opened the InputStream.
I tried switching to channels instead (Files.newByteChannel()). This also allows me to have just one object, and the documentation says it only reads the bytes available and returns the count (which also allows me to implement a timeout). But it blocks in the read method anyway when there is nothing to read, despite what the documentation says.
I also tried a number of ways to implement timeouts on the RandomAccessFile using threads.
The first approach was to start a separate thread at the same time as starting to read, and if the timeout elapsed in the thread I closed the file from the thread, hoping that this would unlock the read() operation with an exception, but it didn't (it stayed blocked).
I also tried to do the read in a separate thread and brutally kill it with the deprecated Thread.stop() once the time had elapsed. This worked one time, but it was not possible to reopen the file again after that.
The only solution I have made work is to have a separate thread that continuously calls read, and whenever it gets a byte it puts it in a LinkedBlockingQueue, which I can read from with a timeout. This approach works, but the drawback is that I can never close the file (again for the same reasons explained above, I can't unblock a blocked read). And my application requires that I sometimes close this connection to the hardware.
Anyone who can think of a way to read from a file with timeout that would work in my case (that allows me to have both a read and a write access open to the file at the same time)?
I am using Java8 by the way.

Java close FileInputStream before reading anything

I have a very peculiar problem. In android I am using FileInputStream to read from the serial (ttySx/COM) port. I am using this to decide which of the known devices is connected (if any at all). What I basically do is:
Are you device 1? No...
Are you device 2? No...
Are you device 3? Yes...
Great lets do some stuff...
And this works great. If there is any incoming data to read (response from device), everything is fine. However, if there is no device connected to ttySx there is nothing to respond to my write. That means nothing to read.
Now, FileInputStream.read() is a blocking call. When I call it in the thread, thread is effectively frozen. I cannot interrupt the thread because for that I would have to read something first. So far everything makes perfect sense.
As there is no response from the port for quite some time I decide that there is nothing connected and want to stop reading and dispose of the thread(actually I do not want to bother with the port anymore because with nothing connected, it is useless to me at this moment). As mentioned earlier interrupt itself is no good. What should be working, is to close() the FileInputStream (read() will throw an exception and hooray!). The close() works... As long as the read() read anything ever (like when I had an answering device connected, then disconnect it -> read() is stuck - because no data to read - but close() works).
However if there was not a thing connected to the port when the read() started (equals: I haven't read a single byte), the close() method does nothing. It does not close the stream. Nor does work the closing of FileInputStream channel.
I could create a workarround: Store the FileInputStream somewhere and when I want to read from the port again later, use the same instance. That would work for me. Unfortunately I would quite unnecessarily block the port itself. No other process (for example another application) could read from the port because it is stuck in "uninterruptable" read...
Any ideas why this is happening and how to make it right? Or some other way to detect if there is anything connected to the ttySx port?
Thanks.
EDIT1: The library used for communication with serial port is https://github.com/cepr/android-serialport-api
In the end we used FileInputStream::available().
First time we tried it, it was like:
Check if anything is available.
Read (regardless of availability)
Of course, when we checked the available, there was nothing to read yet. Then the read call blocked and waited for input. When we checked again, there was nothing available already, because read had cleared the port.
Therefore this suggestion Java close FileInputStream before reading anything from M. Prokhorov was the correct one for my situation.
If anyone would wonder about the behavior in question:
From researching it, it seems that reading streams was not designed for ports/sockets in first place. It was designed for regular files. You read, reach the end of document and close the stream. The exceptions are designed for wrong sequential usage of a stream (you open it, close id and then try to read).
If you enter blocking mode, it will block until it reads at least a byte. No way around it. Close initializes the "closing state" similarly to setting the interrupt state of a thread.

when does FileInputStream.read() block?

The question is similar to the following two questions.
Java InputStream blocking read
Why is the FileInputStream read() not blocking?
But I still cannot fully understand it.
So far I think the read() method in following code will block due to the empty file 'test.txt'.
FileInputStream fis = new FileInputStream("c:/test.txt");
System.out.println(fis.read());
System.out.println("to the end");
Actually it will print -1, I want to know why.
The javadoc says This method blocks if no input is yet available.
What does 'no input is available' mean?
thanks.
The answer to your question can be found in the JavaDoc for .read():
This method blocks if no input is yet available.
and
Returns: the next byte of data, or -1 if the end of the file is reached.
So, an empty file will get you an immediate -1 (instead of read() blocking) as
there is input available, since the file exists
...but it is empty, so immediate EOF.
The ...No input is yet available... situation could occur eg. when one was to read from a named pipe instead of a plain file, and the other side of the pipe hasn't written anything yet.
Cheers,
FileInputStream can be used to read from things other than ordinary files. One obvious example is a named pipe: if you try to read from a pipe before the other side has written to it, the read operation will block.
This maybe interperted as follows: FileInputStream.read invokes a native method, the native method makes the read system call and blocks waiting for OS to read the bytes from file into a buffer and returns when ready. That is, FileInputStream.read uses synchronous I/O to reads data from a file as opposed to non-blocking, asynchronous I/O.
You can't interpret 'no input is available' as 'you are positioned at EOF and no more input will ever be available'. They are different conditions. The latter returns -1.
In general, all reads from files block until the data is available. The disk has to come around to the right point and the head has to seek to the right track. You also need to consider files that are on shared drives, or files that are named pipes, both of which involve network operations, which can also block.

Fast Audio File Output

I've recently finished a small game and have been trying to add audio to it. Currently the sound system I have is working (basically the same code as the top answer here
), but there is a significant stall during every output (~200-300 ms). Since it's a quick game I'm looking for something significant quicker. I'm not experienced with Threads, but would those be applicable here?
Instead of reading the file every time you wish to play its contents in audio format, read the file once into a byte array and then read the audio from that array of bytes.
public static byte[] getBytes(String file) {
RandomAccessFile raf = new RandomAccessFile(file, "r");
byte[] bytes = new byte[(int) raf.length()];
raf.read(bytes);
return bytes;
}
Then, you could simply alter the playSound method to take a byte array as the parameter, and then write them to the SourceDataLine instance to play the sound (like is done in the original method, but it reads them from the file just before it writes them).
You could try passing a BufferedInputStream to the overloaded method AudioSystem.getAudioInputStream() instead of passing a File.
The call to drain is a blocking one and it causes the delays that you observe. You do not need to wait there. However, if you let the sound output operate in parallel with your other code, you should also define what happens if there is a lot of sound in your sound buffers and you are queueing more. Learn about the available method and the rest of the API to be able to manage the sound card flexibly and without any "lagging sound" effects.
Threads can also be used for this purpose, but it is not necessary here. The role of the parallel process can be adequately played by the sound driver itself and the single threaded approach will make your application easier to design and easier to debug.
As much as I'd like to accept one of these existing answers, I solved my problem in a simple way. By loading all the referenced File variables during initialization, the delay does not come back at any point during gameplay. However if this is not an adequate solution for anyone else viewing this question, I would also recommend Vulcan's answer.

Sending buffered data through a socket from Android

I develop the first part of an Android application that allows to broadcast video stream through the network. Currently, I'm sending the video in a very direct way, like this:
Socket socket = new Socket(InetAddress.getByName(hostname), port);
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
recorder.setOutputFile(pfd.getFileDescriptor());
But unfortunately, it is not very fluid. I want to buffered the data stream before sending it through the socket. One of the way I tried is to write the stream in a file using the Android API for recording media, and to use another thread to stream the file to the server on a conputer.
So my problem is: how can I send by a socket a file which is still under writing?
As BufferedInputStream has not a blocking method for reading, I tried to do things like this one, but without any success
while (inputStream.available() >= BUFFER_SIZE) {
inputStream.read(buffer);
outputStream.write(buffer);
}
outputStream.flush();
But when i'm doing that, if the network is faster than the datastream, I get quickly out of the loop.
Is there a 'good' way to do that? I though about doing active waiting but it is not a good solution, especially for mobiles. Another way is to do something like this :
while (true) {
while (inputStream.available() < BUFFER_SIZE) {
wait(TIME);
}
inputStream.read(buffer);
outputStream.write(buffer);
}
outputStream.flush();
But it sound quite dirty for me... Is there sleeker solution?
What I do in these situations if simply fill up a byte array (my buffer) until either I've hit the end of the data I'm about to transmit, or the buffer is full. In which case the buffer is ready to be passed to my Socket transmission logic. Admittedly, I do not do this on video or audio though … only on “regular” data.
Something worth noting is this will give a "janky" user experience to the recipient of that data (it might look like the network is stopping for short periods then running normally again ... the time the buffer is using to fill up). So if you have to use a buffered approach on either video or audio be careful on what buffer size you decide to work with.
For things like video it's been my experence to use streaming based logic versus buffered, but you apparently have some different and interesting requirements.
I can't think of a pretty way of doing this, but one option might be to create a local socket pair, use the 'client' end of the pair as the MediaRecorder output fd, and buffer between the local-server socket and the remote-server. This way, you can block on the local-server until there is data.
Another possibility is to use a file-based pipe/fifo (so the disk doesn't fill up), but I can't remember if the Java layer exposes mkfifo functionality.
In any event, you probably want to look at FileReader, since reads on that should block.
Hope this helps,
Phil Lello

Categories

Resources