I am trying to play a short sound byte after processing a scanned bar code. My code currently works fine for as many as twenty scans. However, eventually the MediaPlayer throws the following error repeatedly even after the app has been killed:
MediaPlayer: Error (-38, 0)
MediaPlayer: Attempt to perform seekTo in wrong state: mPlayer=0xXXXXXX, mCurrentState=0
--the X's representing a random 6 digit memory address--
I originally was playing the sound byte off of the UI thread. Since I've created a handler in an attempt to mitigate the issue. This is how I access the handler:
try {
mHandler.post(mScanFeedback);
} catch (IllegalStateException e) {
System.out.println("Media player state error");
e.printStackTrace();
}
Here is the code for the handler:
private Runnable mScanFeedback = new Runnable(){
public void run() {
if(getString(R.string.working).equals(mStatusHourly)) {
final MediaPlayer mediaPlayer = MediaPlayer.create(getBaseContext(), R.raw.bleep_working);
mediaPlayer.setOnErrorListener(new OnErrorListener() {
public boolean onError(MediaPlayer mp, int what, int extra) {
mediaPlayer.reset();
System.out.println("Media Player onError callback!");
return true;
}
});
mediaPlayer.start();
try {
Thread.sleep(150);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
mediaPlayer.release();
}
} else if(getString(R.string.not_working).equals(mStatusHourly)) {
final MediaPlayer mediaPlayer = MediaPlayer.create(getBaseContext(), R.raw.bleep_not_working);
mediaPlayer.setOnErrorListener(new OnErrorListener() {
public boolean onError(MediaPlayer mp, int what, int extra) {
mediaPlayer.reset();
System.out.println("Media Player onError callback!");
return true;
}
});
mediaPlayer.start();
try {
Thread.sleep(275);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
mediaPlayer.release();
}
} else {
System.out.println("Audio feedback failed as status was indeterminate.");
}
}
};
In the beginning I didn't call release() and adding it hasn't seemed to make it work any better or worse. The onError callback is never called when the problem occurs. I've tried to reset() the media player after each time it is played but that throws an error. Right now I resort to restarting the phone to keep my Logcat from being unusable by the onslaught of the same two error lines repeated continually.
I'm using zxing's bar code scanner and there is a short beep played within that activity as confirmation that the bar code has been captured. A small part of me wonders if their isn't a conflict there.
I'm still new to programming and this is my first question on stack overflow. Let me know if I should have provided any additional information or if I should try to keep it a little more lean.
Update:
I was unable to resolve the issue with the MediaPlayer. However, I was able to work around the issue by switching to a SoundPool implementation. The class below provides the needed functionality.
import java.util.HashMap;
import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;
public class SoundManager {
private SoundPool mSoundPool;
private HashMap mSoundPoolMap;
private AudioManager mAudioManager;
private Context mContext;
public void initSounds(Context theContext) {
mContext = theContext;
mSoundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 0);
mSoundPoolMap = new HashMap();
mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
}
public void addSound(int index, int SoundID) {
mSoundPoolMap.put(index, mSoundPool.load(mContext, SoundID, 1));
}
public void playSound(int index) {
float streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
streamVolume = streamVolume / mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
mSoundPool.play(index, streamVolume, streamVolume, 1, 0, 1f);
}
public void playLoopedSound(int index) {
float streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
streamVolume = streamVolume / mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
mSoundPool.play(index, streamVolume, streamVolume, 1, -1, 1f);
}
}
Which I then accessed from my Activity with:
mSoundManager = new SoundManager();
mSoundManager.initSounds(getBaseContext());
mSoundManager.addSound(1, R.raw.bleep_working);
mSoundManager.addSound(2, R.raw.bleep_not_working);
mSoundManager.playSound(1);
mSoundManager.playSound(2);
Related
This is the method where I create my Mediaplayer and set it's source, but directly after I call seekTo it does't play anymore (If I give it some time-depends on the audio, it worksm--> Conclusion after debug).
public void makeAudio(boolean isInit){
try{
if(!isInit){
mediaPlayer = new MediaPlayer();
}
soundSource = episode.getAudio();
mediaPlayer.setDataSource(soundSource);
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
soundLength = mediaPlayer.getDuration();
seekBar.setMax(soundLength/1000);
mediaPlayer.seekTo(progress);//the problem I guess
}
});
}catch (Exception e){
e.printStackTrace();
}
}
It shows me this error message:
E/MediaPlayerNative: Attempt to perform seekTo in wrong state: mPlayer=0x706c23ebc0, mCurrentState=0
I would like to have any suggestion about this, because I want to make my mediaplayer go to the progress value(I get it from my intent).
I suggest you to use ExoPlayer, it is an improved version of MediaPlayer and addListener works better for online audio.
You have to add listener until it is prepared and only then you can get the duration:
exoPlayer.addListener(new Player.Listener() {
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
if (playbackState == ExoPlayer.STATE_READY) {
long realDurationMillis = exoPlayer.getDuration();
seekBar.setMax((int)realDurationMillis/1000);
dialog.dismiss();
}
if (playbackState == ExoPlayer.STATE_ENDED){
performEndExoPlayer();
}
}
});
Here is an example you can have a look https://developer.android.com/codelabs/exoplayer-intro#5
Let me start by saying that if image shooting interval is anything more than 1 second it works. For example taking a picture every 2 seconds works perfectly fine. But taking a picture every second sometimes throws java.lang.RuntimeException: takePicture failed. What could be causing this kind of a behaviour?
Here is the code I use and it is in Service:
#Override
public void onCreate()
{
super.onCreate();
prefs = getSharedPreferences("general",Context.MODE_PRIVATE);
handler = new Handler();
shotInterval = prefs.getInt(getString(R.string.prefs_int_imageShootingFrequency),1);
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
Toast.makeText(this, "No camera on this device", Toast.LENGTH_LONG).show();
} else {
cameraId = findBackFacingCamera();
if (cameraId < 0) {
Toast.makeText(this, "No front facing camera found.",Toast.LENGTH_LONG).show();
} else {
camera = Camera.open(cameraId);
}
}
cameraParameters = camera.getParameters();
cameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); //set camera to continuously auto-focus
camera.setParameters(cameraParameters);
pictureTaker.run(); // Start looping
}
Runnable pictureTaker = new Runnable() {
#Override
public void run() {
try {
takePicture();
} finally {
// 100% guarantee that this always happens, even if
// your update method throws an exception
handler.postDelayed(pictureTaker, shotInterval*1000);
}
}
};
private void takePicture(){
SurfaceView view = new SurfaceView(this);
try {
camera.setPreviewDisplay(view.getHolder());
camera.startPreview();
camera.takePicture(null, null,new PhotoHandler(getApplicationContext()));
} catch (IOException e) {
e.printStackTrace();
}
}
You should launch postDelayed() from the onPictureTaken() callback. You can check the system timer on call to takePicture() and reduce the delay respectively, to keep 1000ms repetition, but maybe once in a while, this delay will reach 0.
I'm developing an app that uses a ViewPager with one video in each page. Everything works well in every smartphone but it doesn't work in Samnsung GT-I8260 with Android 4.1.2
So in this smartphone, when I compile it returns IOException: Prepare failed.: status=0x1 and it points to mMediaPlayer.prepare();
Now the code is the next:
//First of all I initilize MediaPlayer and I handle the Callback method for SurfaceView
mMediaPlayer = new MediaPlayer();
mSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
mMediaPlayer.release();
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
holder.setSizeFromLayout();
playVideoDelay();
}
#Override
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
}
});
//The app plays the first video with the next method
private void playVideoDelay() {
try {
Uri path = Uri.parse("android.resource://com.casabioclimatica/raw/"+mVideoId);
mMediaPlayer.reset();
mMediaPlayer.setDataSource( mActivity, path);
mMediaPlayer.setDisplay(mSurfaceView.getHolder());
mMediaPlayer.prepare();
if (Build.VERSION.SDK_INT >= 16)
mMediaPlayer
.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
// fis = new FileInputStream(new File(path.getPath()));
//mMediaPlayer.setDataSource(fis.getFD());
} catch (Exception e) {
e.printStackTrace();
}
}
//When ViewPager changes it pages I call this method:
public void playVideoDelay(int videoId) {
try {
Uri path = Uri.parse("android.resource://com.casabioclimatica/raw/"+videoId);
mMediaPlayer.reset();
mMediaPlayer.setDataSource( mActivity, path);
mMediaPlayer.setDisplay(mSurfaceView.getHolder());
mMediaPlayer.prepare();
if (Build.VERSION.SDK_INT >= 16)
mMediaPlayer
.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
Hope somebody has had something similar and knows the proper solution!
Thanks!
After a lot of code changes,I have found the problem in this smartphone, this is because of the maximum resolution. In this case it has 800 x 480 px and I was using 1080 x 800, it was too much and the Dalvik machine interprets that case like this file doesn't exist or doesn't work. I have changed the high and width size of the file and it works like charm!
So for any similar case: Pay attention to your maximum screen supported resolution and try to use this size to avoid any strange error when you render a video.
Hope it helps!
I am trying to write an Android Soundboard with multiple buttons. Each button should play a different sound.
I have a OnClickListener on each button:
buttonAlan.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
playSound("alan");
}
});
Each of these buttons is calling the following function.
private void playSound(String sound) {
int path = getResources().getIdentifier(sound, "raw", getPackageName());
mediaplayer = MediaPlayer.create(this, path);
try {
mediaplayer.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mediaplayer.start();
}
The soundboard works, but everytime you click a button it plays the sound over and over again. I need the mediaplayer to stop playing, but everytime I write something like mediaplayer.stop(), the App won't work at all.
Any suggestions what I should change in my function/code?
i solved it using a soundpool, there you can also play multiple sounds at the same time.
i first initialize it and load sounds i need in the constructor
SoundPool soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
int gameOverSound = soundPool.load(context, R.raw.gameover, 1);
and then you can play it like this:
public void playSound(int soundId) {
soundPool.play(soundId, 1.0f, 1.0f, 0, 0, 1);
}
edit:
regarding the mediaplayer you have to call stop() and release() before you start playing another sound.
also you can set
mPlayer.setLooping(false);
I'm creating a call recording app, when I'm trying to stop call recording the Debug Console in java says that: "MediaRecorder stop called in an invalid state : 4" I've Googled a lot but I can't find anything that can help me! I'm already using RECORD_AUDIO and WRITE_EXTERNAL_STORAGE permissions! Here is part of my code:
private class PhoneCallListener extends PhoneStateListener {
private boolean isPhoneCalling = false;
#SuppressWarnings("deprecation")
#Override
public void onCallStateChanged(int state, final String incomingNumber) {
// TODO Auto-generated method stub
super.onCallStateChanged(state, incomingNumber);
String path = Environment.getExternalStorageDirectory()+"/callrec/";
final MediaRecorder recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL);
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
recorder.setOutputFile(path+"/TEST00000000011110.M4A");
if (TelephonyManager.CALL_STATE_RINGING == state) {
}
if (TelephonyManager.CALL_STATE_OFFHOOK == state) {
isPhoneCalling = true;
try {
recorder.prepare();
recorder.start();
} catch (Exception e) {
}
}
if (TelephonyManager.CALL_STATE_IDLE == state) {
if (isPhoneCalling) {
try {
recorder.stop();
recorder.reset();
recorder.release();
} catch (Exception e) {
// TODO: handle exception
}
Intent i = getBaseContext().getPackageManager()
.getLaunchIntentForPackage(
getBaseContext().getPackageName());
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
isPhoneCalling = false;
}
}
}
}
finally i found a way to fix my problem !
i created a :
public void Recorder()
in my class and when i want to record audio call it
also i created a function for stop recording !
i hope this work for you !
and also this MediaRecorder API works good on android 2.3.3 to 4.3 !