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
Related
I am not sure if this is just an emulator bug or did I miss something. I am writing an alarm app. My app gets a ringtone Uri with RingToneManager, then use MediaPlayer to play the ringtone Uri. I want to control whether the ringtone loops or not. It works fine on my real smartphone, as well as with the Android Studio emulator using Uri gets with RingtoneManager.TYPE_NOTIFICATION and RingtoneManager.TYPE_RINGTONE. However, if I use Uri gets with RingtoneManager.TYPE_ALARM with the emulator, it just keeps looping even if I set mediaPlayer.setLooping(false).
This seems like an emulator bug to me. However, I want to make sure I do not miss something that I need to set. I do not want to find out after the app is released and it turned out that other people's smartphones have the same problem as the emulator. Is there anything I can do or check?
Below is the related code:
activeAlarmSound = new MediaPlayer();
activeAlarmSound.setAudioAttributes(
new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.setUsage(AudioAttributes.USAGE_ALARM)
.build()
);
try {
activeAlarmSound.setDataSource(this, Uri.parse(ringToneString));
if (!hasBGMusic && !timeUpItem.sayDate && !timeUpItem.sayDay && !timeUpItem.sayTime) {
activeAlarmSound.setLooping(true);
} else {
activeAlarmSound.setLooping(false);
}
activeAlarmSound.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
if (playedBGMusic && timeUpItem.getDismissMethod() == 0) {
stopSelf();
} else {
playedAlarmSound = true;
if (activeBGMusic == null) {
playBGMusic();
} else {
activeBGMusic.start();
}
if (timeUpItem.getRepeatAlarm() > 0) {
endAlarmHandler = new Handler();
endAlarmHandler.postDelayed(new Runnable() {
#Override
public void run() {
if (activeBGMusic != null) {
activeBGMusic.pause();
}
playAlarmSoundAndTime();
}
}, timeUpItem.getRepeatAlarm() * 60000);
}
}
}
});
activeAlarmSound.prepare();
activeAlarmSound.start();
} catch (IOException e) {
e.printStackTrace();
}```
Everybody,
I'm trying to make a simple audio recording.
The audio is record perfectly when record button is clicked.
I try to record another audio and play it back. It crash when I try to play the 2nd audio.
Can you please help me on fixing this app so that I can record audio multiple time without crashing the app.
Here's the code.
stop.setEnabled(false);
play.setEnabled(false);
outputFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/recording.3gp";;
myAudioRecorder=new MediaRecorder();
myAudioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
myAudioRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
myAudioRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
myAudioRecorder.setOutputFile(outputFile);
record.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
myAudioRecorder.prepare();
myAudioRecorder.start();
}
catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
record.setEnabled(false);
stop.setEnabled(true);
Toast.makeText(getApplicationContext(), "Recording started", Toast.LENGTH_LONG).show();
}
});
stop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
myAudioRecorder.stop();
myAudioRecorder.reset();
record.setEnabled(true);
stop.setEnabled(false);
play.setEnabled(true);
Toast.makeText(getApplicationContext(), "Audio recorded successfully",Toast.LENGTH_LONG).show();
}
});
play.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) throws IllegalArgumentException,SecurityException,IllegalStateException {
MediaPlayer m = new MediaPlayer();
try {
m.setDataSource(outputFile);
}
catch (IOException e) {
e.printStackTrace();
}
try {
m.prepare();
}
catch (IOException e) {
e.printStackTrace();
}
m.start();
Toast.makeText(getApplicationContext(), "Playing audio", Toast.LENGTH_LONG).show();
}
});
Thanks!
You don't seem to enable record button when stop button is clicked. Write
record.setEnabled(true);
in the onClick() method implementation of stop button.
Another case is when stop button is clicked you are setting myAudioRecorder = null. If after this record button is clicked you will get a NullPointerException on this statement
myAudioRecorder.prepare() //exception
Solution will be to remove the statement of setting myAudioRecorder to null in onClick() implementation of stop.
Another problem comes because of this statement myAudioRecorder.release(). You can't get back the previous instance of MediaRecorder once you have released the resource. Either reinitialize myAudioRecorder each time you record or do not release the resource after stop has been clicked. To look at MediaRecorder lifecycle see this.
Here is a reference code you can look and understand. Please catch exceptions wherever required.
//package name
//imports
public class RecordPlayActivity extends AppCompatActivity implements View.OnClickListener {
// declare buttons here
private MediaRecorder myAudioRecorder;
private String recordOutputFile;
private MediaPlayer mediaPlayer;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(null);
setContentView(R.layout.layout_name);
//find buttons view by Id here
record.setOnClickListener(this);
stop.setOnClickListener(this);
play.setOnClickListener(this);
recordOutputFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/recording.3gp";
myAudioRecorder = new MediaRecorder();
myAudioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
myAudioRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
myAudioRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
myAudioRecorder.setOutputFile(recordOutputFile);
mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(recordOutputFile);
//Initial condition
//stop.setEnabled(false); //not required as stop can be made always enabled
play.setEnabled(false);
}
#Override
public void onClick(View view){
switch(view.getId()){
case R.id.idForRecord:
myAudioRecorder.prepare();
myAudioRecorder.start();
//Recording started
record.setEnabled(false);
// don't make play enabled cause you dont want to play
// and record at same time without stopping record.
play.setEnabled(false); //required because play can get enabled from stop but it should not remain when recording
break;
case R.id.idForStop:
//if clicked after record
myAudioRecorder.stop();
myAudioRecorder.reset();
//if clicked after play
if(mediaPlayer.isLooping()) {
mediaPlayer.stop();
}
//recording stopped and saved;
record.setEnabled(true);
play.setEnabled(true);
break;
case R.id.idForPlay:
mediaPlayer.prepare();
mediaPlayer.start();
//playing
record.setEnabled(false); // you dont wanna play and record at same time
break;
default:
}
}
}`
Hope these all solves your problem.
It's crashing because outputFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/recording.3gp" ; directs to top directory od Android OS ...
If you use this path Environment.getExternalStorageDirectory()+File.separator+"sounds" "/recording.3gp" then your recording will be going into one level down directory "sounds" into directory sounds .
App will not crash if you recording is in folder down from top level path ...
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 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);
I'm making music player app with simple functionality. But when I listen music on my phone with Android 6, sometimes music stops playing until I turn on display again with power button. Then next song is playing, so it seems like it's problem with loading next song. I tried to write new app just to test it out, for this purpose I used this tutorial:
https://code.tutsplus.com/tutorials/background-audio-in-android-with-mediasessioncompat--cms-27030
To this example I added ArrayList with paths to songs. In mediaPlayer onCompletionListener I increase track counter and load new song to media player.
My code:
private void initMediaPlayer() {
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setVolume(1.0f, 1.0f);
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer)
{
onTrackCompletion();
}
});
private void onTrackCompletion()
{
NextTrack();
Play();
}
private void NextTrack()
{
playlistPosition++;
if (playlistPosition == playlists.get(playlistCurrent).size){
playlistPosition = 0;
}
sendAction(ACTION_TRACK_NEXT);
if(mMediaPlayer.isPlaying()){
Pause();
}
loadSong();
Play();
}
private void loadSong()
{
String path = playlists.get(playlistCurrent).getPath(playlistPosition);
if(path == null || path == "")
{
return;
}
try
{
try
{
mMediaPlayer.setDataSource(path);
} catch( IllegalStateException e ) {
mMediaPlayer.release();
initMediaPlayer();
mMediaPlayer.setDataSource(path);
}
initMediaSessionMetadata();
} catch (IOException e) {
return;
}
try {
mMediaPlayer.prepare();
} catch (IOException e) {}
sendTrackData();
}
I don't know anymore why this doesn't work. In manifest I have WAKE_LOCK permission. I also set wake lock for Media player.
Edit:
Today I tried to move loading song into onPlayFromMediaId. I made broadcast from AutoActivity where is Media player to Main Activity and send back onPlayFromMediaId with path to song. But seems like this doesn't work either.I also find out that changing volume with buttons also wake up app.
Edit2:
I made many tests and added debug string in many places in code. And I found out that app stops at mediaplayer.prepare() until I trigger any action on phone (turn on display, volume up/down, click headset button). But I don't know how to fix this bug. I tried to use prepareAsync, but didn't help.
Unless you use foreground service, the system will kill your process and mediaplayer will stop.
below is a part from from a foreground service ( notification example).
builder.setContentTitle(aMessage) // required
.setSmallIcon(R.mipmap.ic_launcher)
.setContentText(this.getString(R.string.app_name)) // required
.setAutoCancel(false)
.setContentIntent(pendingIntent)
.setVibrate(new long[]{0L})
.setPriority(Notification.PRIORITY_HIGH);
int mId = 1489;
startForeground(mId, builder.build());
The above code is tested and working fine.