I am working on application that contacts with media server. So, I have an array that fills with media's URLs. Media type is mp3.
I have a ListView that each row indicates one of array's cell. When clicked event received to each row, It should run setDataSource, prepare and start MediaPlayer. When first time, I clicked on one row, All things are okay and media streams successfully. But when I clicked another while last media is playing, error (1,-114) occurs.
Based on MediaPlayer, I know setDataSource should be run in Idle state of MediaPlayer, So, before setting data source, I invoke reset to move to Idle state.
try {
mediaPlayer.reset();
mediaPlayer.setDataSource(getMusicUrl());
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
mediaPlayer.prepareAsync();
I implement OnErrorListener, The error details is as follows:
What: 1 MEDIA_ERROR_UNKNOWN
Extra: -114 (I haven't found any docs about this error)
Can any one help me to solve this problem?
Could you try calling mediaPlayer.release() when you decide to switch to other song.
Related
I am currently working with FFmpegMediaPlayer in order to make a basic music player given a url. I got the basic functionality to work. On error, I show an error message, else I play the songs.
The problem I am facing is, once the player starts, and I turn off my wifi and phone data, it stops the sound. Once I turn my wifi or phone data back one, I would like the player to continue but it simply stops. I have to stop and play again for it to continue.
Is there a way to have the FFmpegMediaPlayer continue streaming?
This is what I have to initialize the player:
mMediaPlayer = new FFmpegMediaPlayer();
mMediaPlayer.setOnErrorListener(this);
mMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setOnBufferingUpdateListener(this);
mMediaPlayer.setOnSeekCompleteListener(this);
try {
Uri uri = Uri.parse(radio_url);
mMediaPlayer.setDataSource(mMainActivity, uri);
mMediaPlayer.prepareAsync();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Then I have a function to handle when Play/Stop button is clicked:
#Override
public void onPlayButtonClicked(Button button) {
if (radioInitialized) {
mAnalytics.onStopButtonClicked();
mMainLayout.loading(false);
mMediaPlayer.pause();
button.setBackground(mMainActivity.getResources().getDrawable(R.drawable.play_button));
radioInitialized = false;
} else {
mAnalytics.onPlayButtonClicked();
mMainLayout.loading(true);
initRadio();
button.setBackground(mMainActivity.getResources().getDrawable(R.drawable.stop_button));
radioInitialized = true;
}
}
Again, the basic functionality works, but I would like for it to continue streaming after wifi is turned back on.
Found a solution.
My main goal was to create a media player like a radio.
I tried MediaPlayer and it works but it tends to stop frequently.
I then tried vitamio and FFmpegMediaPlayer. Vitamio was confusing and FFmpegMediaPlayer doesn't support on streaming error.
I currently got it working with Google's Exo Player. There is a very nice tutorial here: https://codelabs.developers.google.com/codelabs/exoplayer-intro/index.html?index=..%2F..%2Findex#0
I am trying to work with android Equalizer It works if my app has been started , but fails when another app uses equalizer
the app would crash whenever my app tries to access the equalizer library
Is there a way to know if equalizer is available other wise not to start the activity
here is the code I am trying
Equalizer eq = null;
if (eq != null) {
eq.release();
}
try {
eq = new Equalizer(0, 0);
}
catch (IllegalStateException e) {
fail("Equalizer not initialized");
}
catch (IllegalArgumentException e) {
}
catch (UnsupportedOperationException e) {
}
but I still keep getting the error
java.lang.RuntimeException: java.lang.UnsupportedOperationException: Effect library not loaded
you should call release() on your Equalizer object when you're finished with it. You can't have many instance of Equalizer object.
== UPDATE ==
In your catch block, the one causing issue, you could display a Toast and finish current activity :
catch (UnsupportedOperationException e) {
//display a Toast
finish();
}
I have a custom view (a button) and I want it to have a certain sound when pressed.
private void playSound() {
if (mediaPlayer == null)
initMediaPlayer();
try {
if (mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.prepare();
mediaPlayer.start();
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
private void initMediaPlayer() {
try {
AssetFileDescriptor afd = getContext().getAssets().openFd("music/number_tap.m4a");
mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
} catch (IOException e) {
e.printStackTrace();
}
}
I call the playSound method every time the button is clicked. It works well as long as there is only one button on screen. No problem at all.
It crashes if I have more buttons on the screen and I press the first button a couple of times (works) and then some other button 2 times (crashes on the second press of the second button).
Any idea what could be wrong? Here's the crash stacktrace.
FATAL EXCEPTION: main
Process: com.matejhacin.multiflow, PID: 20991
java.lang.IllegalStateException
at android.media.MediaPlayer._prepare(Native Method)
at android.media.MediaPlayer.prepare(MediaPlayer.java:1163)
at com.matejhacin.multiflow.views.KeyButtonView.playSound(KeyButtonView.java:126)
at com.matejhacin.multiflow.views.KeyButtonView.onTouch(KeyButtonView.java:77)
From what I can see, you have your own implementation of that button KeyButtonView.java, and in that class you have mediaPlayer as a member variable, so when you have two buttons, respectively you have two instances of KeyButtonView class and two instances of mediaPlayer. Why don't you use one instance of mediaPlayer, let's say you make it static, and make playSound() and initMediaPlayer() methods synchronized and static, this should be a quick and simple change, just to test if there is the issue. And something else, you use onTouch() to handle a click, why don't you try with OnClickListener? If you do not use onTouch properly you will end with bunch of calls on the UI thread, and each blocking at prepare(), this is not good. Once you fix this issue, you should consider rewrite it with prepareAsync() and setOnPreparedListener().
I am experiencing an odd issue with a video streaming application I am working on. The actual streaming of video/audio is working fine on all of my test devices. However, on seemingly any device 4.0+, when using an RTSP URL, prepare() returns instantly (this causes an issue providing proper feedback to the users while a video is loading and interferes with a few other systems I have in place).
Below is the block of code where I initialize and setup my MediaPlayer, but keep a few things in mind:
My initPlayer method is called from an AsyncTask.
The video does eventually play correctly, but prepare returning instantly creates a lack of feedback to the user during a video load.
No errors of any kind occur during the entire process
start() is called on the MediaPlayer via the onPrepared method in my OnPreparedListener, which obviously becomes an issue when prepare() returns before it is actually ready to be played.
HTTP streams seem to work fine, and on every test device below 4.0 the issue does not occur.
I have been trying to fix this for a ridiculous amount of time, and haven't been able to find anyone else who has ran into this problem. Any ideas would be greatly appreciated.
public void initPlayer() {
//We first need to make sure the MediaPlayer isn't null
if(mMediaPlayer==null){
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setOnPreparedListener(mediaPlayerPreparedListener);
mMediaPlayer.setOnCompletionListener(mediaPlayerCompletionListener);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
//If a video/stream has been chosen while another is already playing
else if(mMediaPlayer.isPlaying()){
mMediaPlayer.reset();
}
//Video is not in full screen mode
second = false;
try {
mMediaPlayer.setDataSource(videoString);
holder = mPreview.getHolder();
mMediaPlayer.setDisplay(holder);
mMediaPlayer.prepare();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//onPreparedListener
private OnPreparedListener mediaPlayerPreparedListener = new OnPreparedListener(){
public void onPrepared(MediaPlayer mp) {
mp.start();
vidPb.setVisibility(View.INVISIBLE);
}
};
Use mp.prepareAsync() as it is better for streaming media. Using prepare() blocks until MediaPlayer is ready for playback or an IllegalStateException occurs. Also, in android 4 (ICS), blocking on any UI thread is even more strict and may cause an ANR (Activity not responding) dialog to appear.
One final thought, try to avoid using e.printStackTrace(); in android apps.
Instead, use the Log.e("TAG_STRING", e.getMessage(), e); to print errors to the android logging system that you can access from logcat.
All in all, it should looks something like this:
try {
mMediaPlayer.setDataSource(videoString);
holder = mPreview.getHolder();
mMediaPlayer.setDisplay(holder);
mMediaPlayer.prepareAsync();
} catch (IllegalArgumentException e) {
Log.e("TAG_STRING", e.getMessage(), e);
} catch (SecurityException e) {
Log.e("TAG_STRING", e.getMessage(), e);
} catch (IllegalStateException e) {
Log.e("TAG_STRING", e.getMessage(), e);
} catch (IOException e) {
Log.e("TAG_STRING", e.getMessage(), e);
}
I am using a MediaPlayer instance in order to stream audio files from an Internet location. The audio player is in a separate activity. The user can select from a list of audio files and come to this activity to play the audio.
Now the user might go back to the previous activity (with the list) and select another audio file. In this case, I want to stop any other audio that is playing and start playing the new audio which was selected.
Is there any way I can know whether an audio file is playing without having to hold on to the MediaPlayer object?
Thanks.
Edit
I did find out how to know whether an audio is playing.
We can do it by using an object of AudioManager and calling isAudioPlaying(). This will return a true if any audio is playing.
Now the other question, how do I stop an audio currently playing? I do not have an instance of the MediaPlayer object which was created to start the audio (coz the user has already left the activity once and has come back with a new object of the activity and thus a new instance of the MediaPlayer)
You'll need to call stop() on the MediaPlayer instance. To make this work in your application, you'll either need to:
Call stop() within the audio playing activity (in onDestroy()), for example
Create a Service to play audio, and communicate with it from both activities
Using a Service will allow your code to continue running outside of the Activity life-cycle, and is the only way to persist a MediaPlayer object like you need to in this case.
Alternatively, you may be able to create a custom subclass of Application and store the MediaPlayer there, but using a Service is considered better practice.
I found way to check whether audio stream (AudioManager.STREAM_RING, AudioManager.STREAM_NOTIFICATION and etc.) is currently busy using reflection:
/**
* Unhide android api: check is stream is active now (AudioManager.STREAM_RING, AudioManager.STREAM_NOTIFICATION...),
* uses reflection
* #param audioStream
* #return
*/
public static boolean isStreamActive(int audioStream) {
Class<?> audioSystemClazz = null;
Boolean res = false;
try {
audioSystemClazz = Class.forName("android.media.AudioSystem");
if (null != audioSystemClazz) {
// isStreamActive
Method method = audioSystemClazz.getDeclaredMethod("isStreamActive", new Class<?>[] { int.class,
int.class });
if (null != method) {
res = (Boolean) method.invoke(null, audioStream, 0);
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return res;
}
Here's some handy code to sleep until audio is done playing:
AudioManager manager = (AudioManager)this.getSystemService(Context.AUDIO_SERVICE);
while(manager.isMusicActive())
{
Log.d("music", "music is active");
try
{
Thread.sleep(500);
}
catch (InterruptedException e)
{
Log.e("music", "interrupted waiting for music to stop");
}
Log.d("music", "done playing music");
}
#lostintransit "Would it be better to use a service, a static variable or a singleton class? What would be the better design option?"
I think a service is what you want. The built-in media player and Pandora's app both use a service to ensure the music isn't tied to the Activity lifecycle.
If I'm understanding why you'd use a singleton or static I don't think it will accomplish what you want. The singleton/static will only be enforced within a single process in Linux. If you launch your Activity, then close it, then launch it again, they will run in different processes.
Try this...
if (mp1 != null && mp1.isPlaying()) {
mp1.stop();
}
Where mp1 is the MediaPlayer