I want to have two different background music loops playing depending on the state of the app. To do so I tried that code:
private void backgroundMusicPlayer() {
if (gameMode == 0) {
if (backgroundloop2 != null) {
backgroundloop2.pause();
backgroundloop2.stop();
backgroundloop2.release();
backgroundloop2 = null;
}
backgroundloop1 = MediaPlayer.create(getContext(), R.raw.gameloop1);
backgroundloop1.setLooping(true);
backgroundloop1.start();
}
else {
if (backgroundloop1 != null) {
backgroundloop1.pause();
backgroundloop1.stop();
backgroundloop1.release();
backgroundloop1 = null;
}
backgroundloop2 = MediaPlayer.create(getContext(), R.raw.gameloop2);
backgroundloop2.setLooping(true);
backgroundloop2.start();
}
}
But I just get errors:
"MediaPlayer: start called in state 64" "MediaPlayer: pause called in
state 8" "Failed to open libwvm.so: dlopen failed: library "libwvm.so"
not found" "Media Player called in state 0, error (-38,0)"
How can I do it properly?
Why IllegalStateException in onPause()?
In Android Documentation for onPause:
IllegalStateException
If the internal player engine has not been initialized.
In the document, you can see a maximum of media player methods would throw you IllegalStateException for some reason.
So use try catch for all of your media player operations.
Android recommends looking for Exceptions while using media player object.
It is good programming practice to always look out for
IllegalArgumentException and IOException that may be thrown from the
overloaded setDataSource methods.
Related
I am creating a Screen Capturing App. Using MediaRecorder with MediaProjection API.
Getting Run-time Exception while stopping the recorder
Here is the code to stop Screen Capture
private void stop_recorder() {
if (virtualDisplay == null) {
return;
}
virtualDisplay.release();
if (mediaProjection != null) {
mediaProjection.unregisterCallback(projectionCallback);
mediaProjection.stop();
mediaProjection = null;
}
if (recorder != null) {
recorder.stop();
recorder.reset();
}
}
The Exception occur is
E/MediaRecorder: stop failed: -1007
java.lang.RuntimeException: stop failed.
at android.media.MediaRecorder.stop(Native Method)
The Issue is with the emulator. It does not have audio and video source.
Look android.developer doc
RuntimeException is intentionally thrown to the application, if no valid audio/video data has been received when stop() is called. This happens if stop() is called immediately after start().
Solution
Put the mediaRecorder.stop() function in try-catch block
When using the new VolumeShaper in Android O, I am attempting to create it with a MediaPlayer:
// Create a VolumeShaper configuration
VolumeShaper.Configuration volumeShaperConfig =
new VolumeShaper.Configuration.Builder()
.setDuration(3000)
.setCurve(new float[] {0.f, 1.f}, new float[] {0.f, 1.f})
.setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
.build();
mVolumeShaper = mMediaPlayer.createVolumeShaper(configuration);
mMediaPlayer.setDataSource(context, uri);
mMediaPlayer.prepareAsync();
When I try to run it, however, it throws an exception:
Caused by: java.lang.IllegalArgumentException: invalid configuration or operation: -19
at android.media.VolumeShaper.applyPlayer(VolumeShaper.java:189)
at android.media.VolumeShaper.<init>(VolumeShaper.java:54)
at android.media.MediaPlayer.createVolumeShaper(MediaPlayer.java:1392)
In order to create a VolumeShaper, the MediaPlayer object has to be in the "Initialized" state, which happens after calling setDataSource on it. (See: MediaPlayer state diagram.)
In this case it's as simple as changing the code to do it in this order:
mMediaPlayer.setDataSource(context, uri);
mMediaPlayer.prepareAsync();
mVolumeShaper = mMediaPlayer.createVolumeShaper(configuration);
It's also possible to delay the creation of VolumeShaper until calling .start() on the MediaPlayer, and it's worth noting that, with the configuration above, the volume will start off muted, so you'll need to apply the VolumeShaper when starting to play or the output will be silent.
To do this, just use this:
public void play() {
mMediaPlayer.start();
mVolumeShaper.apply(VolumeShaper.Operation.PLAY);
}
To mute it, before pausing or as the track is ending, just apply it in reverse, like this:
public void setMuted(boolean muted) {
if (muted) {
mVolumeShaper.apply(VolumeShaper.Operation.REVERSE);
} else {
mVolumeShaper.apply(VolumeShaper.Operation.PLAY);
}
}
I am facing a really annoying problem with the Widevine Library for Android. For some reason when trying to stream HLS with Widevine some devices (specially Samsung devices) give the following error when trying to play:
WV_Info_GetCodecConfig ESDS returned error 2002
After this, as it does not starts playing I stop, reset and release the media player as well as the DrmClient.
#Override
public void onCompletion(MediaPlayer mp) {
mPlayIndicator.setEnabled(false);
mSurfaceView.setVisibility(View.INVISIBLE);
mTimelineSeekBar.setMax(0);
if (PlayerEnvConfig.USE_DEBUG_LOGGING) {
Log.d("VideoPlayer", "ClosingVideoThread");
}
hideLoading();
if (mScheduleTaskExecutor != null) {
mScheduleTaskExecutor.shutdown();
}
if (mp != null) {
if (PlayerEnvConfig.USE_DEBUG_LOGGING) {
Log.d("VideoPlayer", "Stop Playing");
}
if (mp.isPlaying()) {
mp.stop(); // It's always safe to call stop()
}
if (PlayerEnvConfig.USE_DEBUG_LOGGING) {
Log.d("VideoPlayer", "Reset");
}
mp.reset();
if (PlayerEnvConfig.USE_DEBUG_LOGGING) {
Log.d("VideoPlayer", "Release");
}
mp.release(); // release resources internal to the MediaPlayer
mMediaPlayer = null; // remove reference to MediaPlayer to allow GC
}
// IMPORTANT: It is important to release the DRM client after releasing the media player other wise there are
// situations where the media player it is left in a bad state and does not play any more DRM protected content
// until the restart of the device.
// If the video is DRM protected then release the resource associated with the DRM.
if (mIsDrmProtected) {
mDrmManager.releaseDrmClient();
}
if (!mStopEventFired) {
// Fire the event into the bus to the subscribed views to replace the views accordingly
fireStopVideoPlaybackEvent();
}
}
And the code in the DrmManager to release the DrmClient:
#SuppressLint("NewApi")
public void releaseDrmClient() {
BusProvider.getInstance().unregister(this);
if (mDrmManagerClient != null) {
if (PlayerEnvConfig.USE_DEBUG_LOGGING) {
Log.d("DRMManager", "Releasing DRM");
}
mDrmManagerClient.removeAllRights();
// Starting from API 16 they included this function to release the drm client.
int currentApiVersion = android.os.Build.VERSION.SDK_INT;
if (currentApiVersion >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
mDrmManagerClient.release();
}
// Set to null so will be removed by the garbage collector
mDrmManagerClient = null;
if (PlayerEnvConfig.USE_DEBUG_LOGGING) {
Log.d("DRMManager", "Releasing DRM Finally");
}
}
}
Ok well it does not play. I can confirm that all this code it is executed as they appear in the logs. BUT here is the really big problem, after this situation a process is left in the background (I cannot manage to find anywhere in the device which is the process) as if the video was still being played and the following error is shown constantly in the logs.
WVSession::SetWarning: status=2014, desc=MPEG2-TS continuity counter error
I realised because fir-stable the device gets really hot and second-able a used wireshark to sniff the traffic and I can see the requests made in the background.
This only happens when using HLS and Widevine, and when this last one fails playing. (The rights are actually retrieved and installed correctly but when trying to play fails).
Does anyone have any clue why this could be happening and specially how to avoid it??
Btw: The media player is embedded in a fragment, and this fragment inside another fragment.
Thanks!
I have created a list of songs on click on the song i am able to play the song using MedaiPlayer. While one song is playing if the user clicks another song then i am stopping the media player and starting the player again. But I am getting illegalstateexception in reset(). Here is the code where I am getting the exception. How to stop a player properly? also why am i getting this exception. How to avoid it?
public void stopPlayer() {
try {
if (player != null) {
// Log.e("Trying to Stop "," Player ");
player.stop();
player.release();
player.reset();// causes IllegalstateException
player = null;
}
} catch (Exception e) {
player = null;
playerStatus = false;
e.printStackTrace();
}
}
try this :
player.reset();
player.release();
and also have a look at media player state diagram.
If you want to play again ,then use player.reset(),
player.release() means that it releases the player object so you have to re-intialise the player. So first you use reset() and then release(). release() is used when your player object no longer working. When your activity destroys release() method to be used for good practice.
Whenever you want to stop it:
if(player!=null)
{
if(player.isPlaying())
player.stop();
player.reset();//It requires again setDataSource for player object.
}
Whenever your player no longer to be needed:
if(player!=null)
{
if(player.isPlaying())
player.stop();
player.reset();//It requires again setDataSource for player object.
player.release();
player=null; // fixed typo.
}
Though the accepted answer works, This is a better way to achieve the task
private void stopSong() {
if(mediaPlayer!=null) {
if(mediaPlayer.isPlaying()) {
mediaPlayer.reset();// It requires again setDataSource for player object.
mediaPlayer.stop();// Stop it
mediaPlayer.release();// Release it
mediaPlayer = null; // Initialize it to null so it can be used later
}
}
}
Are you planning on reusing the player again, or are you done with the player? If you're done with the player, call release() and not reset(). If you plan on reusing the player, call reset() and not release().
reset() resets the player to its uninitialized state.
release() frees all resources associated with the player.
The Media Player State Diagram shows, and also states:
Calling stop() stops playback and causes a MediaPlayer in the Started, Paused, Prepared or PlaybackCompleted state to enter the Stopped state.
Once in the Stopped state, playback cannot be started until prepare() or prepareAsync() are called to set the MediaPlayer object to the Prepared state again.
That means, that after calling stop(), we should call prepare() on the same audio file if we wish to play it again. Otherwise calling start() again won't do anything.
As prepare() might throw exception, we should wrap it in a try-catch block, like this:
public void stopAudio(View view) {
mplayer.stop();
try {
mplayer.prepare();
} catch (IOException e) {
Log.e("stopAudio", "Unable to prepare() mplayer after stop()", 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