MediaPlayer.createVolumeShaper throws an IllegalArgumentException: invalid configuration or operation: -19 - android

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);
}
}

Related

Android MediaPlayer IllegalStateExceptoion when called pause()

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.

Play music synchronous using 3 MediaPlayer Objects on Android/Eclipse

What i have:
I have implemented three MediaPlayer.Objects in my App.
All Three are created using a thread:
protected void onResume() {
// Threads
mTT1 = new TrackThread(this, R.raw.audiofile1, 1, mHandler);
mTT2 = new TrackThread(this, R.raw.audiofile2, 2, mHandler);
mTT3 = new TrackThread(this, R.raw.audiofile3, 3, mHandler);
// start thread
mTT1.start();
mTT2.start();
mTT3.start();
super.onResume();
}
"simplified" Code in the Thread for creating:
public class TrackThread extends Thread implements OnPreparedListener {
...
...
...
public void run() {
super.run();
try {
mMp.setDataSource(afd.getFileDescriptor(),
afd.getStartOffset(), afd.getDeclaredLength());
mMp.prepare();
} catch (IllegalArgumentException | IllegalStateException
| IOException e) {
Log.e(TAG, "Unable to play audio queue do to exception: "
+ e.getMessage(), e);
}
}
As I read in several Tutorials the "prepare()" methode takes a little bit of time to finish. Therefore i implemented a "Waiting loop" which waits until all MPs are prepared and created.
When "prepare and create" are done i enable the Start button and i want to start all 3 Mediaplayers SIMULTANEOUSLY.
I again use a Thread for dooing so:
public void onClick(View v) {
// Button 1
if (mBtn.getId() == v.getId()) {
mTT1.startMusic();
mTT2.startMusic();
mTT3.startMusic();
}
Code in the thread:
public class TrackThread extends Thread implements OnPreparedListener {
...
...
...
// start
public void startMusic() {
if (mMp == null)
return;
mMp.start();
}
Please note that the code above is not the full code, but it should be enough to define my problem.
What i want, My problem:
All MPs should play their Music in Sync, unfortunately sometimes when i start the music, there is a time delay between them.
The MPs must start at the exact same time as the 3Audio-files must be played simultaneously (and exactly in sync)
What i have already tried:
+) using SoundPool: My Audio-files are to big(5Megabyte and larger) for SoundPool
+) seekTo(msec): i wanted to seek every MP to a Specific time: eg.: 0, but this did not solve the problem.
+) to reach more Programmers i also asked this question on: coderanch.com
I hope somebody can help me!
Thanks in advance
The bottleneck here will certainly be preparing the mediaplayers to play. The Android framework provides an asynchronous method to perform this loading, and so with a bit of synchronization code you should be able to get these audio sources to play at roughly the same time. To keep from sound artifacting, you'll want less than 10ms of latency.
Initialize an atomic counter, C, to the number of things to load.
Use the prepareAsync() functions within MediaPlayer to prepare all three. Immediately after calling prepareAsync, supply a listener using setOnPreparedListener(listener).
Inside this listener, decrement C and check the value. If the value is greater than 0, wait on an object using the java object .wait() function. If the value is equal to 0, call notifyAll() on the object to wake up all of the other mediaplayer prepared-listener callback threads.
public void startMediaPlayers(List<MediaPlayer> mediaPlayers) {
private AtomicInteger counter = new AtomicInteger(mediaPlayers.size());
Object barrier = new Object();
/* start off all media players */
for (MediaPlayer player : mediaPlayers) {
player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(final MediaPlayer mediaPlayer) {
int value = counter.decrementAndGet();
if (value == 0) {
// all media players are done loading.
// wake up all the ones that are asleep
barrier.notifyAll();
} else {
while (value > 0) {
try {
// wait for everyone else to load
barrier.wait();
} catch (InterruptedException e) {
// ignore
}
}
}
mediaPlayer.start();
callback.success(true);
}
player.prepareAsync();
}
}
As nobody could help me I found a solution on my own. MediaPlayer did not fulfill my requirements but Android JETPlayer in combination with JETCreator did.
CAUTION: Installing Python for using JETCreator is very tricky, therfore
follow this tutorial. And be careful with the versions of python and wxpython, not all versions support the JETCreator.
I used:
Python Version 2.5.4 (python-2.5.4.msi)
wxPython 2.8 (wxPython2.8-win32-unicode-2.8.7.1-py25.exe)
For those who do not know how to implement the Jetplayer watch this video
(at min.5 he starts with programming the Jetplayer).
Unfortunately I do not speak French so I just followed the code which worked for me.
Using Android JETCreator you can create your own JET Files and use them as your resource.
Useful links:
Demo data
Manual
Code/class

getDuration of a mediaplayer error(1, -107)

In my listView I am displaying some media content from an API. The API does not contain any information about the media duration so I thought I'd make a helper class to deal with this.
public static String getPodDuration(String url){
utils = new Utilities();
try{
mep = getInstance();
mep.reset();
mep.setDataSource(url);
mep.prepareAsync();
mep.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
// TODO Auto-generated method stub
duration = mep.getDuration();
Log.i("duration", String.valueOf(duration));
}
});
} catch(IllegalArgumentException e){
} catch(IllegalStateException e){
} catch(IOException e){
}
return String.valueOf(utils.milliSecondsToTimer(duration));
}
The getInstance() is as follows:
static MediaPlayer mep = null;
public static MediaPlayer getInstance(){
if(mep == null){
mep = new MediaPlayer();
}
return mep;
}
So with the help of such methods, in main class I pass on the URL of the media file. But for some reason its only giving me 0:00 value. utils.milliSecondsToTimer(duration) method works fine though.
I get the following error:
error (1, -107)
Can someone help implement this ? I do not have to play this media, I simply need to get its duration.
Edited Response:
The error error (1, -107) is coming from the player engine i.e. NuPlayer engine where the player is trying to connect to the URL. The error code -107 is corresponding to ENOTCONN (reference: errno). Please check the connection of the URL which you have given to the player.
P.S: Can you please try with a file based input?
OLD Response:
The error prepareAsync called in state 8 is indicating that the MediaPlayer is in PREPARED state and hence, it's an error to invoke a prepareAsync in this state. I feel your issue may be due to reset being invoked as part of the implementation. Please refer to this link here which explains the differences between newly created and reset player, especially the paragraph below the state diagram.
I would recommend you to modify your get instance implementation to include a release and remove the reset as below.I feel this should solve your problem.
public static String getPodDuration(String url){
utils = new Utilities();
try{
mp = getInstance();
mp.setDataSource(url);
mp.prepareAsync();
........
static MediaPlayer mp = null;
public static MediaPlayer getInstance(){
if(mp != null){
mp.release();
}
mp = new MediaPlayer();
return mp;
}
You are expecting synchronous output from an asynchronous operation. The prepared callback will not have happened by the time the getPodDuration method returns, so duration will be whatever it was before it entered the method.
Also, you only need to set the prepared listener once. Set it in the same place you create the MediaPlayer. Personally, I'm not a fan of the singleton pattern in this case, but it should still work. Your duration member will need to be static along with the MediaPlayer.

How to stop media player properly , android

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);
}
}

Android MediaPlayer is preparing too long

Hey,
I'm using MediaPlayer to play a regular ShoutCast stream. The code is straightforward with prepareAsync() and a handler to start the playback. While it works flawlessly with some streams like DI.FM or ETN.FM (http://u10.di.fm:80/di_progressive), with others (http://mp3.wpsu.org:8000/) it won't go past the prepare state. No other listeners are called either.
//Uri streamUri = Uri.parse("http://u10.di.fm:80/di_progressive"); /* works */
Uri streamUri = Uri.parse("http://mp3.wpsu.org:8000/"); /* stuck on prepare state */
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(this.getBaseContext(), streamUri);
mediaPlayer.prepareAsync();
Any feedback is appreciated!
I think that there are some compatibility problems with the server end.
This is rather strange since the emulator handles it ok in my case - just not on my Froyo Galaxy S, even though it is the same API version.
It could be a codec issue, http streaming issue, I do not know.
But all the servers that fail tend to be old ones, with "Copyright 1998 - 2004" at the bottom... Not exactly recent or up to date you would think.
One potential workaround (which I have not tried yet) would be to use the StreamProxy, which would also make your code compatible with 2.1 and possibly earlier versions too. At the cost of extra work, extra code, and without doubt extra bugs...
In case you are not aware of it, there is another player bug report for 2.2 which may be relevant too:
Basic streaming audio works in 2.1 but not in 2.2
I'm facing an issue when MP "hangs" at preparing state too long (stream) and i'm trying to stop it using reset(). This causes MP to hang and thus my whole app freezes. Seems like there is no way to stop MP at preparing state. Im thinking on use prepare() wrapped in thread instead of prepareAsync(). Then i'll be able to kill that thread. As for now i did it in following way:
private void actionCancel(){
try {
mp.setDataSource(new String());
} catch (Exception e) {
e.printStackTrace();
android.util.Log.d(TAG,"actionCancel(): mp.setDataSource() exception");
mp.reset();
}
}
and it works 4me.
Additionally i have a following counter:
#Override
public void onBufferingUpdate(final MediaPlayer mp, final int percent) {
if (!mp.isPlaying()){
// android.util.Log.d(TAG,"onBufferingUpdate(): onBufferingUpdateCount = "+onBufferingUpdateCount);
if (onBufferingUpdateCount>MAX_BUFFERING_UPDATES_AT_PREPARING_STATE)
restartMP();
onBufferingUpdateCount++;
return;
}
}
i'd discover this listener always triggers at preparing state. So if it triggers more than 10 times and MP is still not playing i'm just restarting it:
private void restartMP(){
if (mp!=null)
if (mpState==MediaPlayerState.Preparing)
actionCancel();
else
mp.reset();
else
mp = new MediaPlayer();
mpState = MediaPlayerState.Idle;
onBufferingUpdateCount=0;
//isRequestCancelled=false;
requestTrackInfoStartedAt=0;
requestPlay();
}
note MediaPlayerState is my custom enum which has "Preparing" value. Also mpState is a class property/field which holds current MediaPlayerState state. Before starting prepareAsync() im setting mpState to MediaPlayerState.Preparing after it completes im setting it to MediaPlayerState.Started or other corresponding value.

Categories

Resources