I have a Service that starts a thread, where I need to create a MediaPlayer:
Inside onStartCommand I call the main function that runs a thread.
public int onStartCommand(Context context, Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
doTask(context);
return START_STICKY;
}
void doTask(Context context) {
isActive = true;
thread = new Thread(new Runnable() {
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#Override
public void run() {
try {
threadLoop(context);
}
catch (IOException e) {
e.printStackTrace();
}
}
});
thread.start();
Log.e(TAG, "Thread started");
}
After this, inside threadLoop I am trying to create a MediaPlayer
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer = MediaPlayer.create(context, AudioData);
but I can't do anything with the 1st context parameter. I tried to send context and get the base one, but it doesn't work.
Maybe I should use another service for MediaPlayer?
Thank you in advance
Update
Error:
Cannot resolve method 'create(android.content.Context, short[])'.
You're passing in the wrong data to the second parameter. The first parameter is fine. The second is a resource id or a Uri, not a short[]. If the short array is supposed to be audio data (like the raw .wav data), write it to a file and pass it the URI of that file.
Also, passing context to a Thread like that is dangerous and can lead to memory leaks. You need to make sure the thread is ended when the service is ended to prevent it.
Your code should be like this
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer = MediaPlayer.create(this, uri);
Related
I was using MediaPlayer to play sounds in my App but from Its start to freeze the App:
Thats the code where I call create method. I moved the code inside an AsyncTask class :
public class BackgroundSound extends AsyncTask<Integer,Void,Void> {
MediaPlayer mpB;
MediaPlayer mpG;
Context ctx;
BackgroundSound(Context appctx)
{
ctx = appctx;
}
#Override
protected Void doInBackground(Integer... Params) {
switch (Params[0]){
case 0:
mpB = MediaPlayer.create(ctx, R.raw.sonidoemocion5sec);
mpB.setLooping(true);
mpB.setVolume(0.75f, 0.75f);
mpB.start();
break;
case 1:
if (mpG != null)
{
mpG.release();
mpG = null;
}
mpG = MediaPlayer.create(ctx, R.raw.ganador);
mpG.setVolume(1, 1);
mpG.start();
break;
case 2:
if (mpG != null){
mpG.release();
mpG = null;
}
mpG = MediaPlayer.create(ctx, R.raw.perder);
mpG.setVolume(1, 1);
mpG.start();
break;
}
return null;
}
}
Debuging I find that the freeze (app still running but dont make anything) occurred in the new line inside the method create from MediaPlayer.java file::
public static MediaPlayer create(Context context, Uri uri, SurfaceHolder holder,
AudioAttributes audioAttributes, int audioSessionId) {
try {
MediaPlayer mp = new MediaPlayer();
I don't understand what's going on. Any tips?
The warn & Error Log exits:
Instead of using MediaPlayer.create(), use mp.setDataSource() method so that you can call mp.prepareAsync() and then set listener to listen for its completion like this:
mp.setDataSource(this, audioUri);
mp.prepareAsync();
mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
Now for this audioUri object of Uri, you can set it to your audio files in the raw folder by having this line of code in your project:
audioUri = Uri.parse("android.resource://com.yourpackagename/" + R.raw.your_audiofile_name);
This method prepares the mp asynchronously and doesn't block the UI
There are two possible solutions for this issue, but it is not sure that it will work properly as I have not tested it.
Solution 1.
Replace below line:
audiojuego = MediaPlayer.create(this, R.raw.sonidoemocion);
with:
audiojuego = MediaPlayer.create(getApplicationContext(), R.raw.sonidoemocion);
//As you are calling from doInBackground() method, this will not work properly.
Solution 2.
Initialize media player by your own way instead of default.
Uri url=Uri.parse("android.resource://"+getPackageName()+"/raw/sonidoemocion");
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(url);
mediaPlayer.prepare(); // might take long! (for buffering, etc)
mediaPlayer.start();
I have used the following code:
mp = MediaPlayer.create(this, Uri.parse("file://"+filePath));
mp.start();
This works fine. Then I wanted to play music from a folder
mp.setDataSource(this, Uri.parse("file://"+filePath));
mp.prepareAsync();
mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
Are there any performance differences between the two method?
You can check MediaPlayer create() source code to see the difference:
public static MediaPlayer create(Context context, Uri uri, SurfaceHolder holder,
AudioAttributes audioAttributes, int audioSessionId) {
try {
MediaPlayer mp = new MediaPlayer();
final AudioAttributes aa = audioAttributes != null ? audioAttributes :
new AudioAttributes.Builder().build();
mp.setAudioAttributes(aa);
mp.setAudioSessionId(audioSessionId);
mp.setDataSource(context, uri);
if (holder != null) {
mp.setDisplay(holder);
}
mp.prepare();
return mp;
} catch (IOException ex) {
Log.d(TAG, "create failed:", ex);
// fall through
} catch (IllegalArgumentException ex) {
Log.d(TAG, "create failed:", ex);
// fall through
} catch (SecurityException ex) {
Log.d(TAG, "create failed:", ex);
// fall through
}
return null;
}
Basically create() call is synchronous (it internally calls prepare()) and prepareAsync() is asynchronous.
The first approach ties up whatever thread you are on, long enough for MediaPlayer to read in the metadata of the media and prepare some buffers. If this is the main application thread, it means that your UI will be frozen while this is going on.
Sure, create method inits object in main thread. So code lines below it should wait for create.
On the other hand, prepare asynchronous opens a new thread to init object then notify you to run next operations while main thread run other lines.
Edit: As #CommonWares mentioned in the comment, mp.create() is a convenient method of calling mp.setDataSoucer() + mp.prepare() at the same time
for last three weeks I have worked on a Media Player in Android.I am trying to find a solution of how can I make my Media Player to change the song when it's already playing one.
Here is my Listener on the RecyclerView
musicList.addOnItemTouchListener(
new RecyclerItemClickListener(getApplicationContext(), new RecyclerItemClickListener.OnItemClickListener() {
#Override
public void onItemClick(View view, final int position) {
currentPosition = position;
if(!mediaPlayer.isPlaying()){
musicThread.start();
} else {
mediaPlayer.reset();
}
}
})
);
}
and my Thread is this:
final Thread musicThread = new Thread(new Runnable(){
#Override
public void run() {
try {
URL = getMusicURL(myDataset[currentPosition]);
try {
mediaPlayer.setDataSource(URL);
//mediaPlayer.prepare(); // might take long! (for buffering, etc)
mediaPlayer.prepareAsync(); // prepare async to not block main thread
} catch (IOException e) {
e.printStackTrace();
Log.i("TEST","Eroare: "+e.getMessage());
}
} catch (StorageApiException e) {
e.printStackTrace();
Log.i("TEST","Eroare: "+e.getMessage());
}
}
});
I think you have a mess. First of all, you dont need a thread to play music, the own mediaplayer API does it for you when you call mediaPlayer.start(). However, you have to care about the time it takes to prepare the data source if you are for example streaming online music. For this, just use mediaPlayer.prepareAsync() and register a callback. When it has finished preparing, you can automatically start playing or do whatever you want.
If you want to change the data source, just follow the automaton map that you can find in MediaPlayer docs. Essentially, when the user selects another track, you register the call in your button listener, then reset the mediaPlayer, and recall all prepare, start... cycle again. By the way, it is advised to deploy all your mediaplayer code into a service so that it can keep playing even though the user has closed your activity.
I have problems with my app because multimedia sound is heard when the app is in background
I have defined my Media player like this;
private void playLocalAudio(int R1)throws Exception
{
MediaPlayer mediaPlayer = MediaPlayer.create(this,R1);
mediaPlayer.start();
}
For calling PlayLocalAudio I do:
try{
playLocalAudio(R.raw.fartw1);
}
catch (Exception e) {
e.printStackTrace();
}
}});
But I am not able to call correctly MediaPlayer.Stop()
I am trying:
public void onPause()
{
super.onPause();
mediaplayer.stop();
}
But it doesn't work. Could you help me?
I'm guessing that your code has a class variable mediaPlayer that's not visible in your example. In that case you have variable shadowing, because you're instantiating a new mediaPlayer in playLocalAudio and that instance is not visible inside the pause method. So stop is never called. Remove the MediaPlayer class name from the declaration in playLocalAudio.
I am making a music player with a service but when i click a song in the music list, the music starts with no errors, but if i go back to the list and click another i get Attempt to call getDuration without a valid mediaplayer error (-38, 0)
My onStart method in the service:
#Override
public void onStart(final Intent i, int startid) {
Log.d(TAG, "Start music");
re = 0;
songUrl = i.getData().toString();
streamMusic = new Thread() {
public void run() {
Looper.prepare();
try {
re = 1;
music.reset();
music.setDataSource(songUrl);
music.prepare();
this.interrupt();
} catch (Exception e) {
e.printStackTrace();
}
}
};
streamMusic.start();
}
I start the service with startService(i); and I have set a music.setOnPreparedListener so nothing is runned to early.
How do I make it work?
Try calling reset() method before calling prepare again.
Also, if you are calling prepare() and not prepareAsync() I don't see why you need to use the prepared listener.