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.
Related
I am developing a music player and I am almost done. But I need to try something because I have seen there are more commercial music applications use different types of animations for volume up and down while playing the music.
I need something like this,
.
How can I do this? Can anybody help me? Thank you in advance.
If you are outputting your audio via a SourceDataLine, it is possible to inspect the audio data as it is being processed. There is a useful code example of this presented in the Oracle Sound Trail tutorials, on the page Using Files and Format Converters, in the section "Reading Sound Files". The important point in the code is marked with a comment "// Here, do something useful"
At that point you would convert the bytes to audio values, and use the values as part of an RMS calculation. Details for the coversion and the RMS calculation should be searchable--I know I've seen explanations for both on stackoverflow.
Once you have an RMS value calculated, it can be sent to an independent thread that handles the graphics visualization. A loose-coupling pattern should be employed so that you minimize the amount of work being done on the audio thread, and so that you avoid any blocking that might hang up the audio.
For example, the visualization thread can have a setRMSValue method that simply updates an instance variable, without synchronization or blocking of any sort. The audio processing thread can call this method freely as it generates new RMS data points. The visualizer can simultaneously read the current instance variable at your animation rate. No synchronization needed. If the visualization thread skips a few RMS data points, it should not a problem.
I'd like my program to get a file, and then create 4 files based on its byte content.
Working with only the main thread, I just create one DataInputStream and do my thing sequentially.
Now, I'm interested in making my program concurrent. Maybe I can have four threads - one for each file to be created.
I don't want to read the file's bytes into memory all at once, so my threads will need to query the DataInputStream constantly to stream the bytes using read().
What is not clear to me is, should my 4 threads call read() on the same DataInputStream, or should each one have their own separate stream to read from?
I don't think this is a good idea. See http://download.java.net/jdk7/archive/b123/docs/api/java/io/DataInputStream.html
DataInputStream is not necessarily safe for multithreaded access. Thread safety is optional and is the responsibility of users of methods in this class.
Assuming you want all of the data in each of your four new files, each thread should create its own DataInputStream.
If the threads share a single DataInputStream, at best each thread will get some random quarter of the data. At worst, you'll get a crash or data corruption due to multithreaded access to code that is not thread safe.
If you want to read data from 1 file into 4 separate ones you will not share DataInputStream. You can however wrap that stream and add functionality that would make it thread safe.
For example you may want to read in a chunk of data from your DataInputStream and cache that small chunk. When all 4 threads have read the chunk you can dispose of it and continue reading. You would never have to load the complete file into memory. You would only have to load a small amount.
If you look at the doc of DataInputStream. It is a FilterInputStream, which means the read operation is delegated to other inputStream. Suppose you use here is a FileInputStream, In most platform, concurrent read will be supported.
So in your case, you should initialize four different FileInputStream, result in four DataInputStream, used in four thread separately. The read operation will not be interfered.
Short answer is no.
Longer answer: have a single thread read the DataInputStream, and put the data into one of four Queues, one per output file. Decide which Queue based upon the byte content.
Have four threads, each one reading from a Queue, that write to the output files.
Is there a way to have one thread in java make a read call to some FileInputStream or similar and have a second thread processing the bytes being loaded at the same time?
I've tried a number of things - my current attempt has one thread running this:
FileChannel inStream;
try {
inStream = (new FileInputStream(inFile)).getChannel();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
int result;
try {
result = inStream.read(inBuffer);
} ...
And a second thread wanting to access the bytes as they are being loaded. Clearly the read call in the first thread blocks until the buffer is full, but I want to be able to access the bytes loaded into the buffer before that point. Currently, everything I try has the buffer and it's backing array unchanged until the read completes - this not only defeats the point of this threading but also suggests the data is being loaded into some intermediate buffer somewhere and then copied into my buffer later, which seems daft.
One option would be to do a bunch of smaller reads into the array with offsets on subsequent reads, but that adds extra overhead.
Any ideas?
When you read data sequentially, the OS will read ahead the data before you need it. As the system is doing this for you already, you may not get the benefit you might expect.
why can't I just make my Filechannel or FileInputStream "flow" into my ByteBuffer or some byte array?
That is sort of what it does already.
If you want a more seamless loading of the data, you can use a memory mapped files as it "appears" in the memory of the program immediately and is loaded in the background as you use it.
What I usually do with requirements like this is to use multiple buffer class instances, preferably sized to allow efficient loading - a multiple of cluster-size, say. As soon as the first buffer gets loaded up, queue it off, (ie. push its pointer/instance onto a producer-consumer queue), to the thread that will process it and immediately create, (or depool), another buffer instance and start loading that one. To control overall data flow, you can create a suitable number of buffer objects at startup and store them in a 'pool queue', (another producer-consumer queue), and then you can circulate the objects full of data from the pool, to the file-read thread, then to the buffer-processing thread, than back to the pool.
This keeps the file->processing queue 'topped up' with buffer-objects full of data, no bulk copying required, no unavoidable delays, no inefficient inter-thread comms of single bytes, no messy locking of buffer-indexes, no chance that the file-read thread and data-processing thread can ever operate on the same buffer object.
If you want/need to use a threadPool to perform the processing, you can easily do so but you may need a sequence-number in the buffer objects if you need any resulting output from this subsystem to be in the same order as it was read from the file.
The buffer-objects may also contain result data members, exception/errorMessage fields, anything that you might want. The file and/or result data could easily be forwarded on to other thread/s from the data-processing, (eg. a logger or GUI display of progress), before getting repooled. Since it's all just pointer/instance queueing, the huge amount of data wil lflow around your system quickly and efficiently.
I would recommend to use SynchronousQueue. Reader will retrieve data from the queue and writer will "publish" the data from your file.
Use a PipedInput/OutputStream to create a familiar looking pipe with a buffer.?
Also use a FileInputStream to read it byte per byte if necessary. the fis.read() function will not block, it will return -1 if there is no data and you can always check for available();
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?
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