MediaPlayer vs SoundPool for only 1 simultaneous stream - android

I'm working on a game in which one single sound is played each time the phone is shaked.
Does it make sense to use a SoundPool and load sounds in the onCreate of my activity, or is it ok to create a mediaplayer each time, as shown below:
private void onShake() {
MediaPlayer mp= MediaPlayer.create(this, whipSound[currentWhip][force]);
mp.start();
}
My guess is that SoundPool is better because the sounds are loaded only once. Am I right?
Thanks
Julien

As expected, SoundPool is much faster...

You can create the mediaPlayer outside the onShake method, and then reset and start it on every shake:
MediaPlayer mp= MediaPlayer.create(this, whipSound[currentWhip][force]);
...
private void onShake() {
mp.reset();
mp.start();
}
//or
private void onShake() {
try {
mp.stop();
mp.prepare();
} catch (IllegalStateException e) { /* Ignore */
} catch (IOException e) {/* Ignore */ }
try {
mp.start();
} catch (IllegalStateException e) {
Log.e(TAG, "MediaPlayer failed ", e);
}
}

Related

Wait for a sound to end playing. Is this correct?

In my application I need to play a sound in different moments and wait for it to end before doing anything else. Right now I have this code for playing sound:
private MediaPlayer mPlayer = null;
private boolean playSound(){
mPlayer = new MediaPlayer();
try{
mPlayer.setDataSource(openFileInput(fileName).getFD());
mPlayer.prepare();
mPlayer.start();
} catch (Exception e){
e.printStackTrace();
Log.e("player", "error playing sound: "+fileName);
return false;
}
while(mPlayer.isPlaying());
mPlayer.release();
mPlayer = null;
return true;
}
It's not working as I expected: when changing an image before playing the sound the change happens after the sound is played (I suppose it's for the thread queue or something like this)
I don't know if this is a bad solution or if there is any better solution for my case:
the sound playing must start after all previous work is finished.
the app must not do any other work while playing the sound.
the code to execute after the sound playing is not always the same.
You should implement a completion listener:
public class myclass extends .... implements OnCompletionListener, ... {
private int nextAction; // not the smatest solution, but good enough :)
...
private boolean playSound(next){
nextAction = next;
mPlayer = new MediaPlayer();
try{
mPlayer.setDataSource(openFileInput(fileName).getFD());
mPlayer.prepare();
mPlayer.setOnCompletionListener(this);
mPlayer.start();
} catch (Exception e){
e.printStackTrace();
Log.e("player", "error playing sound: "+fileName);
return false;
}
#Override
public void onCompletion(MediaPlayer mp) {
// do your stuff, destroy the mplayer, if needed
switch(nextAction){
case ACTION1: ...; break;
case ACTION2: ...; break; //..and so on
}
}

How can I play a series of short mp3 files with no gap between them in Android?

I have a lot of short .mp3 files that I want to play one after the other.. I tried to use onCompletion event and start the next mp3, though this causes a brief gap between the 2 mp3s..
Here is the code:
void StartSound() {
mediaplayer = MediaPlayer.create(this, Uri.parse(FILE_PATH + counter + ".mp3"));
try {
mediaplayer.start();
mediaplayer.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
counter++;
try {
mp.reset();
mp.setDataSource(FILE_PATH + counter + ".mp3");
mp.prepare();
} catch (Exception e) {
e.printStackTrace();
}
mp.start();
}
});
} catch (Exception e) {
}
}
Is there a work around to this issue?
There's a workaround, but whether it's worth the trouble is up to you.
The basic idea is to decode the MP3 files to a PCM buffer, stitch them together in a byte array, and play with an AudioTrack. Seamless MP3 playback doesn't really exist with MediaPlayer. This could be a pain in the ass, though, and memory problems are likely if you're talking about full songs. For short clips, it may work, but SoundPool might be the better option.
If you're just trying to narrow the gap a bit, you can try preparing the following MediaPlayer objects before onCompletionListener. Instead of waiting to be done, prepare the next two so you can start playback faster. Then when you hit onCompletion, you can just flip which object you're using and start(). Crude double buffering, in a way.
Try this:
public class MainActivity extends Activity
{
private int[] tracks = {R.raw.explosion,R.raw.pianothingy_one,R.raw.car_horn_x};
int mCompleted = 0;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MediaPlayer mp = MediaPlayer.create(this, tracks[0]);
mp.setOnCompletionListener(new OnCompletionListener()
{
#Override
public void onCompletion(MediaPlayer mp)
{
mCompleted++;
mp.reset();
if (mCompleted < tracks.length)
{
try
{
AssetFileDescriptor afd = getResources().openRawResourceFd(tracks[mCompleted]);
if (afd != null)
{
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
mp.prepare();
mp.start();
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
else if (mCompleted>=tracks.length)
{
mCompleted =0;
try
{
AssetFileDescriptor afd = getResources().openRawResourceFd(tracks[mCompleted]);
if (afd != null)
{
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
mp.prepare();
mp.start();
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
else
{
mCompleted=0;
mp.release();
mp = null;
}
}
});
mp.start();

android Mediaplayer not playing too fast

I have a MediaPlayer object through which i am playing a sound on click of a button.the sound file is 1-2 second long only.When i am clicking the corresponding button one after another(quickly), it's not playing the sound twice(it is playing just once.I tried with some code like this :
public void onClick(View view) {
if(DrawSound.isPlaying()) {
DrawSound.stop();
DrawSound.prepareAsync();
}
DrawSound.start();
}
it's not wokring.Search a lot, but could make it work.Any help!!!!
Try using prepare instead of prepareAsync
This is because you are not releasing media player after its completed playing your sound ... use release and reset method in Media Players setOnCompletionListener Method...
you can use it like this ...
if(mp.isPlaying()) {
try {
mp.stop();
mp.reset();
mp.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
mp.start();
}
or you can use it ...
mp.stop();
mp.prepareAsync();
mp.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
This is working fine for me.
Hey guys if someone can get help from this:
just solve my problem with a trick(after all trick can do all :p)
i took 2 MediaPlayer object and one MediaPlayer reference and wrote like this :
soundPlayer = DrawSound.isPlaying() ? DrawSound1 : DrawSound;
soundPlayer.start();
Try this and see if it works:
if(DrawSound.isPlaying()) {
DrawSound.stop();
DrawSound.prepareAsync();
DrawSound.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
DrawSound.start();
}
});
}

Media Player called in state 0, error (-38,0)

I am currently trying to design a simple app that streams an internet radio station. I have the URL for the station and am setting up the Media Player like
MediaPlayer mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(URL);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
mediaPlayer.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
mediaPlayer.start();
The program isn't crashing when emulated, but nothing is playing and I am get the following error:
start called in state 0
and right below it is
Error (-38,0)
Does anyone know what this means?
I've read a little about these state errors, but couldn't find anything that applies to my project.
You need to call mediaPlayer.start() in the onPrepared method by using a listener.
You are getting this error because you are calling mediaPlayer.start() before it has reached the prepared state.
Here is how you can do it :
mp.setDataSource(url);
mp.setOnPreparedListener(this);
mp.prepareAsync();
public void onPrepared(MediaPlayer player) {
player.start();
}
It seems like Error -38 means a state-exception (as the error-message indicates). For example if you call start(), before the song was ready, or when you call pause(), even if the song isn't playing at all.
To fix this issue check the state of the mediaPlayer before calling the methods. For example:
if(mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
Additionally, the MediaPlayer is sending event-messages. Even if you do not need the prepared-event (although it would be a good idea to not start the playback before this event was fired) you must set a callback-listener. This also holds true for the OnErrorListener, OnCompletionListener, OnPreparedListener and OnSeekCompletedListener (if you call the seek method).
Listeners can be attached simply by
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
// Do something. For example: playButton.setEnabled(true);
}
});
I got this error when I was trying to get the current position (MediaPlayer.getCurrentPosition()) of media player when it wasn't in the prepared stated. I got around this by Keeping track of its state and only calling the getCurrentPosition() method after onPreparedListener is called.
This is my code,tested and working fine:
package com.example.com.mak.mediaplayer;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.app.Activity;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final MediaPlayer mpp = MediaPlayer.create(this, R.raw.red); //mp3 file in res/raw folder
Button btnplay = (Button) findViewById(R.id.btnplay); //Play
btnplay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View vone) {
mpp.start();
}
});
Button btnpause = (Button) findViewById(R.id.btnpause); //Pause
btnpause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View vtwo) {
if (mpp.isPlaying()) {
mpp.pause();
mpp.seekTo(0);
}
}
});
}
}
I encountered the same issue few days ago. My audio MediaPlayer works fine on devices with high processing power, but for slow devices, the media player just did not play some time and from LogCat it had many complain about called in wrong state. So I resolved it by calling putting the call to start(), pause(),... in onPrepared() method of OnPreparedListener() as below:
mediaPlayer.prepare();
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
........
mediaPlayer.start();
....
songControlBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
} else {
mediaPlayer.start();
}
}
});
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
............
}
});
}
});
Also try to release any media player that you do not need any more. For example, if you do not want to play the audio or video on background then you should call mediaPlayer.release() in onPause().
i tested below code. working fine
public class test extends Activity implements OnErrorListener, OnPreparedListener {
private MediaPlayer player;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
player = new MediaPlayer();
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
player.setDataSource("http://www.hubharp.com/web_sound/BachGavotte.mp3");
player.setOnErrorListener(this);
player.setOnPreparedListener(this);
player.prepareAsync();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onDestroy() {
super.onDestroy();
player.release();
player = null;
}
#Override
public void onPrepared(MediaPlayer play) {
play.start();
}
#Override
public boolean onError(MediaPlayer arg0, int arg1, int arg2) {
return false;
}
}
Some times file are encoded in a way that Android can't decode. Even some mp4 files can not be played. Please try a different file format (.3gp are played most of the time) and see..
You get this message in the logs, because you do something that is not allowed in the current state of your MediaPlayer instance.
Therefore you should always register an error handler to catch those things (as #tidbeck suggested).
At first, I advice you to take a look at the documentation for the MediaPlayer class and get an understanding of what that with states means. See: http://developer.android.com/reference/android/media/MediaPlayer.html#StateDiagram
Your mistake here could well be one of the common ones, the others wrote here, but in general, I would take a look at the documentation of what methods are valid to call in what state: http://developer.android.com/reference/android/media/MediaPlayer.html#Valid_and_Invalid_States
In my example it was the method mediaPlayer.CurrentPosition, that I called while the media player was in a state, where it was not allowed to call this property.
above the picture,you can get the right way.
I solved both the errors (-19,0) and (-38,0) , by creating a new object of MediaPlayer every time before playing and releasing it after that.
Before :
void play(int resourceID) {
if (getActivity() != null) {
//Using the same object - Problem persists
player = MediaPlayer.create(getActivity(), resourceID);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
player.release();
}
});
player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
}
}
After:
void play(int resourceID) {
if (getActivity() != null) {
//Problem Solved
//Creating new MediaPlayer object every time and releasing it after completion
final MediaPlayer player = MediaPlayer.create(getActivity(), resourceID);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
player.release();
}
});
player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
}
}
if(length>0)
{
mediaPlayer = new MediaPlayer();
Log.d("length",""+length);
try {
mediaPlayer.setDataSource(getApplication(),Uri.parse(uri));
} catch(IOException e) {
e.printStackTrace();
}
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.seekTo(length);
mediaPlayer.start();
}
});
mediaPlayer.prepareAsync();
It was every much frustrated. So, I got solution which works for me.
try {
if (mediaPlayer != null) {
mediaPlayer.release();
mediaPlayer = null;
}
mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(file.getAbsolutePath());
mediaPlayer.setAudioStreamType(AudioManager.STREAM_NOTIFICATION);
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
});
}
});
mediaPlayer.prepare();
} catch (Exception e) {
e.printStackTrace();
}
For me this worked
mp.seekTo(0);
mp.start();
I also got this error i tried with onPreparedListener but still got this error. Finally i got the solution that error is my fault because i forgot the internet permission in Android Manifest xml. :)
<uses-permission android:name="android.permission.INTERNET" />
I used sample coding for mediaplayer. I used in StreamService.java
onCreate method
String url = "http://s17.myradiostream.com:11474/";
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(url);
mediaPlayer.prepare();
mp = new MediaPlayer();
AssetFileDescriptor afd = mContext.getAssets().openFd(fileName);
mp.reset();
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
mp.prepare();
mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
mp.prepareAsync();
I have change setAudioStreamType to setAudioAttributes;
mediaPlayer.setAudioAttributes(AudioAttributes.Builder()
.setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
.setLegacyStreamType(AudioManager.STREAM_ALARM)
.setUsage(AudioAttributes.USAGE_ALARM)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build());
I am new in android programming and i had same error as this one. so i simply redefined the mp.createmediaPlayer = MediaPlayer.create(getApplicationContext(), Settings.System.DEFAULT_RINGTONE_URI). It may not the true way to do it but it worked fined for me:
try {
mp = MediaPlayer.create(getApplicationContext(), Settings.System.DEFAULT_RINGTONE_URI);
} catch (Exception e) {
e.printStackTrace();
}
mp.start();

Android: Imagebutton, onclick play sound

I'm a noob trying to work something out and learn from it.
I have two imagebuttons and when i click them I get a kind of "schick" sound rather than the sound files that i have in the /res/raw/ directory.
This is my code:
public void button_clicked1(View v)
{
text1.setText("1"+width);
mp = MediaPlayer.create(GameScreen.this, R.raw.a);
mp.start();
}
public void button_clicked2(View v)
{
text1.setText("2"+height);
mp = MediaPlayer.create(GameScreen.this, R.raw.b);
mp.start();
}
What am I doing wrong?
Thanks!
Ok, changed the above code to this:
public void button_clicked1(View v)
{
text1.setText("1"+width);
mp = MediaPlayer.create(GameScreen.this, R.raw.piano_a);
try {
mp .prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
mp.start();
}
public void button_clicked2(View v)
{
text1.setText("2"+height);
mp = MediaPlayer.create(GameScreen.this, R.raw.piano_b);
try {
mp .prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
mp.start();
}
And it still does not work
EDIT: Try this:
setVolumeControlStream(AudioManager.STREAM_MUSIC);
in your main application code. This will tell the AudioManager that when your application has focus, the volume keys should adjust music volume (found that here).
After that, make sure that your volume is up - it may just be playing the sounds with no volume.

Categories

Resources