How to properly cancel MediaPlayer.prepare()? - android

I am using the Android MediaPlayer to play a Video in my app.
I use MediaPlayer.prepare() instead of MediaPlayer.prepareAsync() deliberately, because I want to be able to know when the statement is finished so that I can, for example, hide a progress bar.
I realize that I could do this with a MediaPlayer.prepareAsync(), but since this would create an ugly overhead in my code, would only be used for this detection and probably wouldn't help in this situation anyway, I don't want to do that.
When I start my activity with the video loading and I try to go back to the previous activity before it finished MediaPlayer.prepare(), it throws an IllegalStateException.
All the steps I take before that are synchronized, so just catching the Exception and ignoring it would be possible here, however, I don't want to have throwing and catching an Exception as expected behavior if I can avoid it.
I've already tried to call MediaPlayer.reset() while MediaPlayer.prepare() is running, but the same thing happens.

Related

Use of SuperpoweredAndroidAudioIO interface

I create SuperpoweredAndroidAudioIO for recording, and it starts working right away, which is fine. However, when I try to use the .onForeground() method when the android activity calls .onResume() it causes a crash... Even if I call onBackground() during onPause().
I also never call start()/stop(), and things seem to work find without calling any of these methods. I can't tell if it's draining battery, and why the methods fail or aren't seemingly needed.
http://superpowered.com/docs/_superpowered_android_audio_i_o_8h_source.html
How should I be using these appropriately?

AsyncTask thread never ends

I'm using an app that uses async tasks to do short term background calculation jobs. These seem to end OK (go through onPostExecute() etc), but in the Eclipse debugger, one or more still hangs around.
Then I found this link - AsyncTask threads never die - so OK, it's about a thread pool and in theory not an issue.
Problems is however, I am also trying to use Google in-app billing code V3, and that appears to throw an exception whenever you carry out a purchase and there's already an AsyncTask thread hanging around. Catching the exception won't help - it still won't do anything.
How can I get around this? What do I need to do to guarantee the old calculation thread(s) have gone?
Found out what is going on here, and it wasn't what I thought. I'll detail it here as it may be useful to somebody. Has nothing to do with other AsyncTask threads and thread pooling.
In the IabHelper class are two functions flagStartAsync() and flagEndAsync(). The aim of these is to produce a single pass gate (bit like wait() and signal() in traditional multi-threading) so only one async operation (that is, communications with Google Play and the server) can occur at a time. If flagStartAsync() get called while something is already going on, it produces an exception. Not terribly graceful, but effective I guess.
The flagStartAsync() 'test and set' gets called at the start of launchPurchaseFlow() among other places, and flagEndAsync gets called in handleActivityResult() - again - among other places. So providing the purchase flow does something that always produces a result, no problem. The problem is - it doesn't always.
If you look at launchPurchaseFlow() there are several paths out that will not kick off the async operation, and if one of those get taken, mAsyncInProgress (the relevant flag) gets left set.
What blew it in my case was that I hadn't checked that the item was already purchased, and 'already purchased' is one of the paths out. Mea culpa, but the problem is that I cannot convince myself that there aren't several other paths that you just cannot avoid at times. What if operation is slow and the 'purchase' button gets pressed twice, for instance? I bet there are others as well. One could catch the exception, and that would stop a crash, but it wouldn't really help if nothing came along to clear the flag in the end. I guess the exception handler could call flagEndAsync() but it has an uncomfortable 'sledgehammer to crack a nut' feel.
It strikes me that this is probably a non-robust piece of code. What I've done for now is call flagEndAsync() in the various ways out of launchPurchaseFlow(), but that is just a temporary fix. I don't know enough about the IabHelper code, but I think it needs more careful thought and I need to analyse it to see everything it does.

Mediaplayer error once used multiple times

I've created a game which is nearly complete, but I've still got one problem:
Once I press a button I want a sound to play, I did this with this code:
MediaPlayer planeSound = MediaPlayer.create(ObjectCanvas.getDrawContext(), R.raw.plane);
planeSound.start();
It works perfectly, but the only problem is when I press it a lot of times, then the MediaPlayer gives a error which is error (-19,0). I searched but I can't find a solution for this. If the error happens the MediaPlayer won't play any sounds anymore untill the actvity is recreated. The game doesn't get a FC, but just the error (-19,0).
I don't know how to fix it, I hope someone can give me some suggestions or explanation.
Go for sound pool, or reuse one instance of media player, or release each instance once you have finished with it.
When done with the MediaPlayer, you should call release(), to free the
resources. If not released, too many MediaPlayer instances will result
in an exception.
etc
It is also recommended that once a MediaPlayer object is no longer
being used, call release() immediately so that resources used by the
internal player engine associated with the MediaPlayer object can be
released immediately. Resource may include singleton resources such as
hardware acceleration components and failure to call release() may
cause subsequent instances of MediaPlayer objects to fallback to
software implementations or fail altogether. Once the MediaPlayer
object is in the End state, it can no longer be used and there is no
way to bring it back to any other state.
See the documentation: http://developer.android.com/reference/android/media/MediaPlayer.html

Check to see if Android MediaRecorder is Recording

I've written some code for Android 2.2 that plays an audio file using the Android MediaPlayer. Without getting into the details of the code, I noticed that there exists a function called
isPlaying()
that allows you to check if an audio file is currently being played by the MediaPlayer. So, for example, when the following snippet of code runs
Toast.makeText(getApplicationContext(), "Sound playing is: " +
mediaPlayer.isPlaying(), Toast.LENGTH_SHORT).show();
it displays the following message
Sound playing is: true / false
depending on whether there's sound playing or not.
When I wrote some code to record sound from the microphone using the Android MediaRecorder, however, I noticed that there did not look like there exists a function called
isRecording()
that checks to see whether a recording is in progress.
So, I was wondering if the onus is on the programmer then to figure out if a recording is in progress by embedding some logic into their code - or if perhaps there indeed exists a way to do this (check if a recording is in progress) by using another in-built function offered by the Android API.
Doesn't look like there is such a function after all. I think it makes sense to try to embed some logic in the code to do this cleanly.
Important
I found a nice workaround to handle this issue, and you can read the workaround right away, but I strongly suggest that you read the entire explanation first.
The scenario
I was trying to find a way to figure out if the mediarecorder had started recording or not, I assumed that calling the start() method on the recorder after the prepare() method was enough, but it turns out, it isn't.
Before you get offended by what I just said, Let me explain the scenario...
I was building a simple audio recording app from scratch, no libraries, copy paste, all hardwork. So I knew exactly what each part of my code is doing. Or at least I thought I did.
Until I decided to try and break my application by clicking on the buttons to start and stop recording like I was playing a piano. And yes, my stop button wasn't even appearing until the mediarecorder's start() method was called.
So I was greeted with a crash and logcat welcomed me with
java.lang.RuntimeException: stop failed.
at android.media.MediaRecorder.stop(Native Method)
along with
E/MediaRecorder(15709): stop failed: -1007
So I read online and found out that calling stop() right after start() on MediaRecorder causes this problem.
So the biggest question was, how do I detect if it is now SAFE for me to enable the STOP button on my recorder?
The Workaround (Not at all perfect, but it works)
MediaRecorder.getMaxAmplitude() // The maximum absolute amplitude measured since the last call, or 0 when called for the first time
As you can see, the MediaRecorder.getMaxAmplitude() method or the MediaRecorder.maxAmplitude property return 0 when called for the first time and the amplitude after that.
So, instead of allowing the user to Stop the recording right after calling MediaRecorder.start() I am now waiting until the MediaRecorder.maxAmplitude value is greater than zero, at which point I can be sure that the MediaRecorder is initialized, started, and recording, and is in a state where calling stop() is allowed. You can accomplish this by using a runnable that keeps checking until the amplitude is greater than 0. I am already using a runnable for the timer, so I perform the check in that.
Please Note
When working on an emulator, the value returned by MediaRecorder.maxAmplitude is always 0. So, you should use an Android Device to check if everything works as expected.
Now my buttons stay disabled for less than a second when I first start recording. But if I stop and start too quickly, they remain disabled for a bit longer, and I show a "Please wait while the recording starts" message for the user.
I hope this answer helps someone.
Regards!

Does RecognitionListener.onError() automatically SpeechRecognizer.cancel()?

For various reasons, I need to use the raw SpeechRecognizer API instead of the easier RecognizerIntent (RECOGNIZE_SPEECH) activity.
That means, among other things, that I need to handle RecognitionListener.onError() myself.
In response to some of the errors, I simply want to re-start listening. This looks straightforward but when I just call SpeechRecognizer.startListening() upon error, this sometimes seems to trigger two different errors:
ERROR/ServerConnectorImpl(619): Previous session not destroyed
and
"concurrent startListening received - ignoring this call"
Which hints that I should have done some cleanup before attempting to call SpeechRecognizer.startListening() again.
If this is true, it means that upon a RecognitionListener error, listening is not automatically stopped and/or canceled.
It is also possible that some errors do stop/cancel listening, while others don't. There are really only 9 SpeechRecognizer errors:
ERROR_NETWORK_TIMEOUT
ERROR_NETWORK
ERROR_AUDIO
ERROR_SERVER
ERROR_CLIENT
ERROR_SPEECH_TIMEOUT
ERROR_NO_MATCH
ERROR_RECOGNIZER_BUSY
ERROR_INSUFFICIENT_PERMISSIONS
Since the documentation isn't very detailed about which error cancels listening and which doesn't, do you happen to know, based on your experience, which errors require doing cleanup (and to which extent) before attempting SpeechRecognizer.startListening() again?
No, cancel is not called when onError is invoked. You can look at the source here.
you can destroy current session by destroy(). And you can restart it again
Actually Femi, some of the error conditions DO stop the transcription service from listening (SpeechRecognizer.ERROR_SPEECH_TIMEOUT for example). It is not necessary to call destroy, just startlistening again.

Categories

Resources