I am using a FileInputStream in a thread in Android java to read from a serial interface file. stream.read(buffer) blocks if there is not data waiting right now, if new data comes in again is continues. Data arrives every now and then, whenever something comes in the thread continues running. That's perfect!
But when I want to terminate the thread it seems I stumble upon a long known bug. thread.interrupt() does not cancel stream.read().
There are lots of questions about that. The only thing that should work is to close the underlying stream. But if I close my FileInputStream stream.read() in my receiver thread still keeps waiting. It only stops after receiving the next bunch of data - that of course then goes a wrong way.
What else can I do to really close or shutdown the FileInputStream?
Edit
After discussing my solution looks like this. It's not best performance and uses available() which is not advised in the docs but it works.
The thread that listens to the file:
byte[] buffer = new byte[1024];
while (!isInterrupted())
{
if (stream.available() == 0)
{
Thread.sleep(200);
continue;
}
// now read only executes if there is something to read, it will not block indefinitely.
// let's hope available() always returns > 0 if there is something to read.
int size = stream.read(buffer);
now do whatever you want with buffer, then repeat the while loop
}
The sleep duration is a tradeoff between not looping all the time and getting data in an acceptable interval. The Mainthread terminates this with
stream.close(); // which has no effect to the thread but is clean
thread.interrupt();
I guess there is nothing you can do with that blocking read operation. Try the available to check if there is available data before reading.
while(!isInterrupted()) {
int len = 0;
if(len = inputStream.available() > 0)
// read your data
}
Here is another option: How to stop a thread waiting in a blocking read operation in Java?
I also meet the same question, But I didn't find the official solution.
So I implemented a method according to my own business scenario.
class ReadThread extends Thread {
pubulic void run() {
while(flag) {
int size = inputStream.read(buffer);
if(flag) {
// do something
}
}
}
}
when I want to exit this thread, I will set flag = false. Even this thread is not really exit, suppose the inputStread read someting, I will not handle it.
Related
Before you tell me that I should not kill threads and instead send a signal/set a flag for them to react, let me explain the scenario:
I'm developing an audio player in Android NDK with OpenSL API (play a local mp3 file), but the Android implementation has a bug where If I perform repeatedly a seek operation on the file, the thread sadly hangs in a kind of internal deadlock when I try to free resources (SLObjectItf->Destroy).
So I moved the destroy routine to a child thread and wait for a fixed amount of time for it to finish, if it doesn't, I consider the thread as hanged and continue execution leaking some resources, which is preferable than having to go to the system settings and manually kill the app.
I tried to kill the child thread with pthread_kill using the signals SIGTERM and SIGKILL, but it seems both are terminating my whole application and Android restarts it. I cannot use pthread_cancel because the thread is hanged and also that method is not supported on Android NDK.
Is there any way to kill the child thread without killing the entire app?
EDIT: Here is the thread and the code starting it
static void *destroyDecoderInBackground(void *ignoredArgument)
{
if (decoderObject != NULL)
{
__android_log_print(ANDROID_LOG_INFO, "OpenSLES", "Destroying decoder object");
(*decoderObject)->Destroy(decoderObject);
__android_log_print(ANDROID_LOG_INFO, "OpenSLES", "Decoder object destroyed");
decoderObject = NULL;
decoderPlay = NULL;
decoderSeek = NULL;
decoderBufferQueue = NULL;
}
pthread_mutex_lock(&destroyDecoderLock);
pthread_cond_signal(&destroyDecoderCond);
pthread_mutex_unlock(&destroyDecoderLock);
pthread_exit(0);
}
static void destroyDecoder(JNIEnv* env)
{
logJava("Trying to destroy decoder");
struct timespec timeToWait;
struct timeval now;
// get absolute future time to wait
clock_gettime(CLOCK_REALTIME, &timeToWait);
timeToWait.tv_nsec = timeToWait.tv_nsec + (500 * 1000000);
// wait for destroy decoder thread to complete
pthread_mutex_lock(&destroyDecoderLock);
pthread_create(&destroyDecoderThread, NULL, &destroyDecoderInBackground, NULL);
logJava("Starting waiting");
pthread_cond_timedwait(&destroyDecoderCond, &destroyDecoderLock, &timeToWait);
pthread_mutex_unlock(&destroyDecoderLock);
logJava("Finished waiting");
if(decoderObject != NULL)
{
logJava("Destroy decoder hanged, killing thread, resources will leak!!!");
pthread_kill(destroyDecoderThread, SIGTERM);
decoderObject = NULL;
decoderPlay = NULL;
decoderSeek = NULL;
decoderBufferQueue = NULL;
}
}
From the pthread_kill man page:
Signal dispositions are process-wide: if a signal handler is
installed, the handler will be invoked in the thread thread, but if
the disposition of the signal is "stop", "continue", or "terminate",
this action will affect the whole process.
In Dalvik the signals used for special handling (e.g SIGQUIT dumps the stacks, SIGUSR1 causes a GC) are blocked before any threads are created, and then unblocked in the SignalCatcher thread using sigwait(). You can't alter the block status for the threads you don't control, so this won't work for you.
What you can do instead is install a signal handler for an otherwise unused signal (e.g. I don't think SIGUSR2 is used by shipping versions of Dalvik), and have it call pthread_exit(). As noted in the man page for that function:
When a thread terminates, process-shared resources (e.g., mutexes,
condition variables, semaphores, and file descriptors) are not
released, and functions registered using atexit(3) are not called.
This sounds like the "desired" behavior.
Having said all that, please don't give up on the hope of not doing this. :-) It sounds like you recognize part of the problem (resource leaks), but you also have to consider the possibility of inconsistent state, e.g. mutexes that think they're held by the thread that exited. You can end up in a state where other threads will now hang or act strangely.
Hey I am currently designing an app where some code gets executed every 200ms. The thread I use for this looks like this (simplified):
final Handler handler = new Handler();
Runnable runnable = new Runnable()
{ public void run()
{
handler.postDelayed(this, 200);
switch (status){
case 1: check(1);p2.setBackgroundColor(0x00000000); p1.setBackgroundColor(0xDDCC0000); status = 2; break;
case 2: check(2);p1.setBackgroundColor(0x00000000); p2.setBackgroundColor(0xAAAA0000); status = 1; break;
}
}
}; runnable.run();
check() contains some non-UI code lines.
The problem is, that the postDelayed-200-ms start, when the queue is fully executed and not at the beginning so all time that the system needs to execute the commands stacks and stacks all the time so these are actually ~210-230ms (depending on CPU load)
Then I tried to get the system date at the beginning of the thread and add 200ms to it but this results in some other, "heavier" errors.
I have no problem with more than 200ms delay, I just want to get it running stable.
I hope you understand my problem and can give some advice to me.
EDIT: I know got to know that the Handler runs acceptable (delay of 4ms on 200ms). The problem are the methods I am calling then. I will open a new question
If check() contains non-ui code lines then you should run those in a separate thread.
The bottom line is that the UI thread is *really busy, so, you can ask it to do something every 200ms but you aren't guaranteed any precision since the Device is doing its best to do all sorts of other things. When you say "heavier problems" what do you mean exactly?
I would try to start a Thread and just Log every 200ms to see if the device is willing to accurately do *anything at the rate you wish. If it does, then you can send messages to the UI thread to draw and if you find that its the drawing that is delayed, then perhaps you need to reduce your delay to give the UI thread time to finish drawing? (obviously this is also highly imprecise and will vary wildly from device to device).
Did you try doing it using Timers? A basic implementation would look like
new Timer().scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
// TODO Auto-generated method stub
}
}, 200, 200);
You can try using the alarm service as well. that should give you accurate (or at least consistent) results.
Apparently no exception is thrown so that I can recognize an error while buffering streaming audio content. For example I've disconnected my router and the app will continue to try to buffer the whole time. When I reconnect then it completes buffering and continues even after being disconnected for over a minute!
So the problem is I can't let my user sit there for that long without considering that a problem. What is the proper method to detect a buffering problem with the Android media player?
I'm thinking about using a Timer for a timeout. I'll start probably with 15 seconds (using a proxy I tested a 5kbps connection, which would be a worst case, was able to start playing in 6-10 seconds, so I think 15 seconds would be a reasonable timeout period). Does this sound like a good plan? If so should I create a new Timer with each buffer attempt or should I keep the same Timer throughout the lifetime of the playback service?
So basically I'm asking two questions:
1) What's the proper way to detect if a buffer is having a problem? Is there a listener I'm overlooking? I've tried MediaPlayer.OnErrorListener of course that doesn't fire in my tests. My conclusion is I have to have a timeout to detect a buffering error.
2) If I'm correct on number one, what is the proper way to use a Timer? Create one with each buffer attempt or reuse the same one? EDIT Also should I restart the (or cancel and create a new) Timer onBufferUpdate? With the onBufferUpdate listener I should know that some data is coming back so should maybe reset the timer with that.
From your question, I understand that the primary objective is to detect a situation if your player is stalled due to buffering and take some actions thereof. To handle this situation, I feel that the following 2 listeners may be helpful to identify the same.
MediaPlayer.onBufferingUpdate would provide the timely progress of the buffering. So, if there are 2 callbacks with same percent value, this could be an indication of potential buffering.
There is another listener MediaPlayer.onInfoListener which has some specific events which could be of interest to you. On this listener, if the what is MEDIA_INFO_BUFFERING_START, this would indicate that the player is pausing the playback for buffering i.e. trigger for your logic. Similarly MEDIA_INFO_BUFFERING_END indicates the restart of the playback after filling the buffers.
You Should see this article. The mediaplayer has a ErrorListener to get any error.
http://developer.android.com/reference/android/media/MediaPlayer.OnErrorListener.html
int count=40;//for 40 seconds to wait for buffering after it will finish the activity
//boolean timeoutflag=false;
timeout = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
System.out.println("value of count="+msg.getData().getLong("count"));
if (msg.getData().getBoolean("valid")) {
if (msg.getData().getLong("count") == 0 && !timeoutflag)
{
if (pDialog != null && pDialog.isShowing())
{
try
{
pDialog.dismiss();
}catch(Exception e)
{
e.printStackTrace();
}
}
Toast.makeText(getApplicationContext(),
"Unable To Load This Video", Toast.LENGTH_LONG).show();
finish();
} else {
}
}
}
};
timeout.postDelayed(null, 0);
new Thread(new Runnable() {
#Override
public void run() {
while (count > 0) {
try {
Thread.sleep(1020);
} catch (Exception e) {
}
Message msg = new Message();
Bundle b = new Bundle();
b.putBoolean("valid", true);
b.putLong("count", --count);
msg.setData(b);
timeout.sendMessage(msg);
}
}
}).start();
// set timeoutflag=true; in setOnPreparedListener of video view
For buffering during preparation, you have to set your own timer which calls player.reset() after some interval. This puts the player back into init state.
For buffering after preparation (during play) you have to monitor getPosition(). If it falls behind some maximum, call reset(). This allows you to set an experience threshold for your playback. Handles not only failed connection, but also choppy connection.
Best solution is to not use MediaPlayer. Use a public VLC derivative instead. MP has too many internalized private design limitations requiring horrible workarounds (eg. CANT add codecs). RTFM gives you false hope in this case.
Unless you are doing a very straight laced android app, don't depend on any android api. Some opensource substitutes are better supported, and for good reason.
(really bandeely olly jolly satisfying editorial rant deleted)
My application has a UI (implemented with an Activity) and a service (implemented with the IntentService). The service is used to send data (synchronous, using NetworkStream.Write) to a remote server as well as to update the transmission status to the UI (implemented using Broadcast Receiver method).
Here is my problem:
The application works properly if the size of the buffer used for the NetworkStream.Write is 11 KB or less.
However, if the size of the buffer is larger than 11 KB, say 20 KB (this size needed in order to send jpg images), then the sevice keeps working properly (verified with log file), nonetheless the UI its gone (similar as if device's back button is pushed) and I can't find the way to bring it back. Its important to point out that in this case the Activity its not going into OnStop() nor OnDestroy() states.
At first I thought this would be some ApplicationNotResponding related issue due to a server delay, yet the UI crashes after about 5 sec.
Moreover, this only happens with the Hardware version. The emulator version works fine.
// SEND STREAM:
Byte[] outStream = new Byte[20000];
// -- Set up TCP connection: --
TcpClient ClientSock = new TcpClient();
ClientSock.Connect("myserver.com", 5555);
NetworkStream serverStream = ClientSock.GetStream();
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
// . . .
// RECEIVE STREAM:
inStream.Initialize(); // Clears any previous value.
int nBytesRead = 0;
nBytesRead = serverStream.Read(inStream, 0, 1024);
// -- Closing communications socket: --
ClientSock.Close();
One thing first: I would have been commented the question to clarify one thing before I give an answer, but unfortunately I don't have enough reputation yet.
The thing I would have asked for is: Why do you need to have a buffer greater than 11k to send an JPG image?
I nearly do the same in one (async) task with an image of 260k, but with a buffer of 10240 Bytes. Works without difficulties.
byte[] buffer = new byte[10240];
for (int length = 0; (length = in.read(buffer)) > 0;) {
outputStream.write(buffer, 0, length);
outputStream.flush();
bytesWritten += length;
progress = (int) ((double) bytesWritten * 100 / totalBytes);
publishProgress();
}
outputStream.flush();
I use this part to read an JPG image from resources or SD and post to my server.
Well you may want to change your application to use asynctask and take a look to the guide :
http://developer.android.com/training/basics/network-ops/connecting.html
Network operations can involve unpredictable delays. To prevent this from causing a poor user experience, always perform network operations on a separate thread from the UI.
Since android 4.0 it's impossible to perform network related task in the same thread as the UI thread. Also just to be clear http://developer.android.com/guide/components/services.html
Caution: A service runs in the main thread of its hosting process—the
service does not create its own thread and does not run in a separate
process
I'm facing a problem where I want to play a half second long AudioTrack in static mode repeatedly, but the sound is choppy. However, I noticed that the sound is perfectly clear while a TransitionDrawable is running in parallel.
A simplified skeleton of my code is:
thread = new Thread(new Runnable() {
public void run() {
createTransition();
try {
createAudioTrack();
while (true) {
if (audio) {
playSoundClip();
}
if (display) {
playScreenTransition();
}
Thread.sleep(getDelayBetweenBeats());
}
} catch (InterruptedException e) {
} finally {
resetScreenTransition();
stopSoundClip();
}
}
private void createAudioTrack() {
short[] samples = generateSamples();
track = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLERATE, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, samples.length * 2, AudioTrack.MODE_STATIC);
if (track.getState() != AudioTrack.STATE_UNINITIALIZED) {
track.write(samples, 0, samples.length);
}
}
private void playSoundClip() {
if (track != null && track.getState() != AudioTrack.STATE_UNINITIALIZED) {
track.stop();
track.reloadStaticData();
track.play();
}
}
private void playScreenTransition() {
view.post(new Runnable() {
public void run() {
view.setBackgroundDrawable(transition);
transition.startTransition(DURATION);
}
});
}
});
thread.start();
As you can see thread is not performed on the UI-thread so I assume that the track is facing multithreading problems. I don't think that the UI-thread that plays the transition consumes the entire CPU since my audio is playing in parallel. It seems as if the activity somehow consumes the CPU and nothing else is executed.
I had tried to use view.post(new Runnable() {...}); in playSoundClip(), too, but that didn't help.
I thought about changing all into an AsyncTask, but IMHO that wouldn't change anything as it would still be a background task. Since I don't need to update an UI-element with the sound and the transition still has to play in parallel I didn't even try that.
A solution would probably be to always have some transition running in parallel (the actual one or a dummy one), but that just sounds bad (pun?) to me.
Does anyone know of another way how I can make track play clear at all times?
EDIT:
After working some more in this issue and extending my program I noticed that I have to use a threaded approach like I lined out above as the logic in there takes some time to complete and I can't do it all on the UI-thread any more. Currently I play a dummy transition while the audio is playing, which still sounds bad to me. Therefore, if you can still contribute some insights into this topic you are welcome to post/answer them here.
You might want to take a look at SoundPool, which would allow you to statically load your short audio sample into memory once and then play it on-demand with much lower latency. The way in which you are using AudioTrack is a good use of replaying the audio without reloading, but it might still be a bit heavy-weight for such a short and often repeated sound byte.
You might also consider not using a background thread at all. It looks from your snippet like you are really just using the Thread as a timer, and you might get better performance out of using a Handler to post your Runnable on a timed interval (which would also allow you to call your audio/transition methods on the main thread) instead.
HTH
I have much larger chunks of audio but I have had luck playing them in a Service that I created.
P.S. Nice Pun