MediaPlayer onCompletion is not being called accurately - android

In my app i have created an audio player (only WAV files) using MediaPlayer API.
But the player doesn't give callback to onCompletion Listener everytime. Sometimes it gives callback but not everytime. I am doing some audio processing on wav file , like insertion and overwriting.
Is it because any missing in audio header?
Why it doesn't give callback when the playback is completed?

Make sure that the headers of file is set correctly. If somethings in header is missing callback to the onCompletion may not occur.
If mediaplayer is playing a .wav file, seeking may happen correctly but a jerking will be there . So when the playingback completes there will be a differecnce of 0-1000 ms between total duration of file and onCompletion respectively. So if such a situation comes you should guess that as onColmpletion and do what you wanted. Thats a bit tricky way to get the onCompletion.
I faced the same problem while playing a .wav file with the mediaplayer. This is not a good way to solve this issue, but I tackled the same problem like this when i was having the same situation. Hope this will help you too in some ways.

It seems you have to call setOnCompletionListener AFTER calling start().
Take a look here: https://stackoverflow.com/a/19555480/1860130
Worked for me.

In order to get the onCompletion() function called you should disable looping with a call mediaPlayer.setLooping(false);

Make sure the MediaPlayer is not a local(temporal) variable. Since the local variable will be collected by GC. In that case, the onCompletion will have no chance to be invoked.

You're using the correct Method but have you passed any code in the
"// do some tasks here when playback completes " AREA.
If not then the callback wont make any sense.
mMediaPlayer.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
Toast.makeText(getApplicationContext(),"Playback Completes", Toast.LENGTH_SHORT).show();
}
});
This method will pop a Toast on completion of playback.

Return true to OnErrorListner method on MediaPlayer
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
//Invoked when there has been an error during an asynchronous operation
switch (what) {
case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
Log.e("MediaPlayer Error", "MEDIA ERROR NOT VALID FOR PROGRESSIVE PLAYBACK " + extra);
break;
case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
Log.e("MediaPlayer Error", "MEDIA ERROR SERVER DIED " + extra);
break;
case MediaPlayer.MEDIA_ERROR_UNKNOWN:
Log.e("MediaPlayer Error", "MEDIA ERROR UNKNOWN " + extra);
break;
}
return true;
}

Try to use a sleep method once recording is completed.
Also use; .prepare() before the placeback occurs , to avoid crashes.

Related

MediaPlayer Error (1, -1004)

I have searched too much here on stack overflow but I am unable to find any solution of my problem.
I am getting a Media Player Error named 'MEDIA_ERROR_IO' code -1004.
I am stream an audio from server everything works good. song prepared and then starts in onPrepared() method.
Now the problem comes when there is an incoming call and phone starts ringing, and I pauses the song by calling mediaPlayer.pause() from my BroadcastReceiver class.
when the Phone call ends start the audio again by calling mediaPlayer.start()
the audio starts but after 2-3 seconds it stops with an Error that is MediaPlayer error (1, -1004).
Now What should I do?
Any Help is appreciable.
Thank you.
the audio starts but after 2-3 seconds it stops with an Error that is
MediaPlayer error (1, -1004).
First, Lets understand what error (1, -1004) means. -1004 is the error code for IO error. Below reference from MediaPlayer.java source code.
/** File or network related operation errors. */
public static final int MEDIA_ERROR_IO = -1004;
This type of error comes if for some reason, the media player is not able to connect to the server due to network issues. It could be bad internet connectivity at that instance or some network related reason due which the media player was unable to connect to the server. There are some other similar error codes that the media player can throw like time-outs or server died:
/** Some operation takes too long to complete, usually more than 3-5 seconds. */
public static final int MEDIA_ERROR_TIMED_OUT = -110;
/** Media server died.*/
public static final int MEDIA_ERROR_SERVER_DIED = 100;
Now What should I do?
To handle errors generated by media player at run time, you should implement Error Listener. You can handle the error in which ever way as you like for example restart the player.
mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
switch(extra){
case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
// Do Something
// eg. reset the media player and restart
break;
case MediaPlayer.MEDIA_ERROR_IO:
// Do Something
// eg. Show dialog to user indicating bad connectivity
// or attempt to restart the player
break;
case MediaPlayer.MEDIA_ERROR_TIMED_OUT:
//Do Something
//eg. Show dialog that there was error in connecting to the server
// or attempt some retries
break;
}
//You must always return true if you want the error listener to work
return true;
}
});

What means the message "internal/external state mismatch corrected" at the MediaPlayer?

I work with a MediaPlayer and set the state of the player often programmatically like for example:
if(mp.isPlaying()) {
mp.pause();
animationPausedMusic();
}
private void animationPausedMusic() {
// Changing button image to play button
btn_play.setBackgroundResource(R.drawable.play);
... // more code
}
But sometimes the logcat gives me the message:
"internal/external state mismatch corrected"
And then the play and pause function is not working anymore.
What does this message mean? And how can I solve it?
After going through the android's native framework for media player I found that in source file mediaplayer.cpp inside function bool MediaPlayer::isPlaying() The developer is checking if the currentState of media player is in STARTED state and yet the media player is not playing any media, so it tries to change the state to PAUSED state so that the state consistency should be maintained for API users.(and here is where he is printing the message "ALOGE("internal/external state mismatch corrected");")
Now If you go through the media player state diagram below:
You would notice that this may happen when the MediaPlayer moved to 'STARTED' state after a call to start() and at this time for some obscure reason has not yet started the playback and you fire a MediaPlayer.isPlaying() method call , The Framework treat this as state inconsistency and moves to 'PAUSED' state and that's why you cannot see anything playing further.
However, if someone has some better understanding please share your thoughts!
I ran into this recently, and like some other questions say, it's this bug (marked obsolete alas)
https://code.google.com/p/android/issues/detail?id=9732
I found this error occurs when playing a MIDI file, but only sometimes. It happens when mp.isPlaying() is called quickly after mp.start()
If you can manage to not call mp.isPlaying() for a little bit, the error doesn't occur. In my case, a 10th of a second or so made the difference between getting the error or not. It's awkward, but it works.
e.g.
//setting a new track
mp.setDataSource(path);
mp.prepare();
mp.start();
//calling mp.isPlaying() here or shortly after starts the problem
//since we know it's playing, we can store that state, or call
updateUiPlaying(); //eg instead of updateUi();
//or just call some code here that takes more time first
updateScaledImages(); //something that might take time
Log.v(TAG, "mp.isPlaying = " + mp.isPlaying()); //now isPlaying() shouldn't cause that error
Also, I put a check in when I pause later.
mp.pause()
if(mp.isPlaying()){
//shouldn't be playing, must be in error
mp.stop();
mp.release();
mp = new MediaPlayer();
//any other initialization here
}
Though the problem doesn't occur if there is a wait before calling isPlaying()
Apparently there is more than one cause of this message. The following solution worked for me. It may or may not work for you. I called the method MediaPlayer.reset() immediately after instantiating the MediaPlayer object:
MediaPlayer mp = new MediaPlayer();
mp.reset();

How can I send a pre-recorded(wav) file during a voice call?

I want to develop an application through which if the caller calls you, the call should be answered automatically without user's involvement and the caller could hear a pre-recorded voice which is already recorded and saved.The audio file should be in .wav format.I searched for help in google but i came to know that it is not possible in Android but there are some android applications which have the same functionality.So i think there is some possibility for this.Excuse me if the question is wrong.I would be grateful if some one help me.I am using eclipse Helios with ADT Plugin. I've tried the below code but it didn't work out.If someone know the answer please help me out. I've used broadcast receiver to read the phone state changes.In CALL_STATE_OFFHOOK, i wrote the following code.
case TelephonyManager.CALL_STATE_OFFHOOK:
Toast.makeText(context, "Call Picked..", Toast.LENGTH_LONG) .show();
Log.d("received", "Call Picked....");
final MediaPlayer mPlayer = MediaPlayer.create(context, R.raw.music_file);
mPlayer.setAudioStreamType(AudioManager.STREAM_VOICE_CALL);
mPlayer.prepareAsync();
mPlayer.start();
mPlayer.setOnErrorListener(new OnErrorListener() {
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
// TODO Auto-generated method
mPlayer.reset();
return true;
}
});
AudioManager am=(AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
am.setMode(AudioManager.MODE_IN_CALL);
am.setSpeakerphoneOn(false);
am.setMicrophoneMute(true);
Log.d("in call","sent audio");
mPlayer.reset();
mPlayer.release();
break;
Piping audio into a phone call is completely unsupported by Android hardware.
"Auto Call Answer" by DevIndia Infoway is on the playstore. It works by playing back an mp3 while switching the handsfree on. So the other party will hear what is played (and also if there is other noise in the room). Not really rocket-science.

VideoView looping videos Replenish

I have an application with a VideoView that will keep looping the same video over and over until a user does something to the device(touch screen, etc) Currently I am using the OnCompletionListener() to restart the video once it ends. This works properly on every device I have tested, except for the Samsung Replenish.
Here is my code:
mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mVideoView.setVideoPath(file.getAbsolutePath());
mVideoView.start();
}
});
What happens on the Replenish is the video plays all the way through once but then is never started again and the screen goes all black (But backlight still turned on). On every other device I've tested on with this exact same code it has worked to repeat the video. Does anyone know of anything specific about the Replenish that could cause this error? I thought maybe delaying the calls to setVideoPath(), and start() by 200-300ms might help it, but that had no affect. I am really at a loss here.
I am seeing these messages in my Log:
ERROR/QCvdec(87): Omx Flush issued when vdec is not initialized yet.
ERROR/QCvdec(87): OMXCORE-SM:Recieved command DISABLE (2)
ERROR/QCvdec(87): Omx Flush issued when vdec is not initialized yet.
ERROR/QCvdec(87): OMXCORE-SM:Recieved command ENABLE (3)
But these logs are happening both when the video starts (the first time it plays) and when it fails to start again. so I am not sure if they are related to my problem
Edit:
I just tried setting mVideoView to null, and then getting a new reference to it with findViewById() right before the setVideoPath(). I know this would complicate the way the OnCompletionListener is set up. But regardless of that it didn't work anyway, still the same dark screen.
Edit 2:
I've started to notice that sometimes the video doesn't even start the first time. I am using these same two lines to start it up the first time:
mVideoView.setVideoPath(file.getAbsolutePath());
mVideoView.start();
It seems to start more consistantly, but not quite 100% when its the first time it is being played.
Edit 3: This is how I have it set up now. I am manually setting the OnPreparedListener to start the video for me. So I added this to my onCreate()
mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer arg0) {
mVideoView.start();
}
});
Then when I am ready to restart the video I just call only the setVideoPath() method, Like this:
mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mVideoView.setVideoPath(file.getAbsolutePath());
}
});
This seems to be doing the trick. I am letting it run for a while to find out for sure though.
Edit 4:
#MByD In the code for VideoView setVideoPath() is a wrapper for setVideoUri(). setVideoURI() is setting mStartWhenPrepared = false; The default OnPreparedListener checks this switch to decide whether to start playback or not. That is why it doesn't start with the default listener. I haven't looked into it more than that, but there may be a setter method that lets me change the mStartWhenPrepared value to true, which would cause the video to be started from the default listener.
Have you tryed to prepare() your video before you call .start()?
from the docs: http://developer.android.com/reference/android/media/MediaPlayer.html#prepare%28%29
with a OnPreparedListener you can start your video when its ready.

DTMF tone in RecognitionListener.onReadyForSpeech() mistaken for speech

The Google Voice Search comes with a significant delay from the moment you call it via startActivityForResult() until its dialog box is displayed, ready to take your speech.
This requires the user to always look at the screen, waiting for the dialog box to be displayed, before speaking.
So I was thinking of generating an audible signal instead of the dialog box by implementing RecognitionListener and sounding a DTMF tone in onReadyForSpeech() as in the following snippet:
#Override
public void onReadyForSpeech(Bundle params) {
Log.d(LCTAG, "Called when the endpointer is ready for the user to start speaking.");
mToneGenerator.startTone(ToneGenerator.TONE_DTMF_1);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
Log.e(LCTAG, "InterruptedException while in Thread.sleep(50).");
e.printStackTrace();
} // SystemClock.sleep(50);
mToneGenerator.stopTone();
}
The tone sounds beautifully but... it is also "heard" by the microphone, arriving to the voice recognition service and always generating a recognition error ERROR_NO_MATCH.
Is there a way to work around this?
Here is a random idea, and it may very well not work.
Can you try disabling the microphone (maybe via AudioManager.setMicrophoneMute) while the tone is played?
Here's my code that's working for me, put into the onReadyForSpeech() callback of the RecognitionListener.
private void playSpeechReadyTone(){
audioManager.setMicrophoneMute(true);
MediaPlayer mediaPlayer = MediaPlayer.create(JarvisService.this, R.raw.doublebeep);
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer arg0) {
audioManager.setMicrophoneMute(false);
}
});
mediaPlayer.start();
}
I'm afraid that there isn't an easy&clean way to do that. As srf appointed, you shouldn't rely on AudioManager.setMicrophoneMute(boolean), so, AFAIK, the possibles are:
Play an audio file before call SpeechRecognizer.startListening(intent):
final MediaPlayer mediaPlayer = MediaPlayer.create(JarvisService.this, R.raw.doublebeep);
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer player) {
player.release();
// Safety start Speech Recognizer
mSpeechRecognizer.startListening(getSpeechRecognizerIntent());
}
});
mediaPlayer.start();
However, this solution has a problem... If may receive an RecognitionListener.onError(int error) before RecognitionListener.onReadyForSpeech being called and, in that case, you are still playing a beep sound every time (this will happen, for example, if you are not connected to the Internet and Speech Recognition is configured to work online)!
Besides, you should manage the case of cancelling the speech recognition process during audio (doublebeep) play.
Play the audio in the onReadyForSpeech callback (read original question) but use RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS with an appropriate value. In my case, my beep sound is really short (1 second max) and I set RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS to 4/5 seconds.
Also note that, as Google doc says:
Note also that certain values may cause undesired or unexpected results - use judiciously! Additionally, depending on the recognizer implementation, these values may have no effect.

Categories

Resources