I'm using a MediaController and MediaPlayer together, to create a simple audio player in Android, taken from an example I found here on this site.
However, after much search I could not find the solution to my problem: the progress/seek bar doesn't refresh while the music is playing. It just updates itself when something on the MediaController is pressed (Play/Pause, forward, etc).
Any easy fix for this that I'm not getting ?
NOTE: My MediaController is declared in XML, and my MediaController.MediaPlayerControl methods just make use of the MediaPlayer class.
Mediaplayer provides a method getCurrentPosition() you can put this in a thread to continously update the progressbar.
public int getCurrentPositionInt(){
if (player != null)
return player.getCurrentPosition();
else
return 0;
}
Create a Thread or CountDownTimer to continuously update the seekbar :
seekBar.setMax((getCurrentPositionInt() / 1000));
OR
MediaController.MediaPlayerControl mp;
mp.seekTo((getCurrentPositionInt() / 1000))
Im Sorry for my English!
you are showing the controller before the music player is ready.
You need to notify your activity from the controller when it is ready.
public void onPrepared(MediaPlayer mp) {
mp.start();
Intent onPreparedIntent = new Intent("MP_READY");
LocalBroadcastManager.getInstance(activity).sendBroadcast(onPreparedIntent);
}
Then you need to create a BroadcastReceiver in your activity and override his onReceive method to show the controller.
private BroadcastReceiver mpReadyReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context c, Intent i) {
controller.show(0);
}
};
You also need to register the receiver in your activity`s onResume().
protected void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(this).registerReceiver(mpReadyReceiver,
new IntentFilter("MP_READY"));
}
Now try to call controller.show only when it is necesary.
Be careful not creating more than one controller instance
Related
I'd like to play music across Activities and I'm using a simple class to implement it. This class ( BackgroundMusic ) starts the music with MediaPlayer when I call the startMusic() method and stops it when I call the stopMusic() method. When I use it only in one Activity it works perfectly. OnCreate calls startMusic() method and onPause calls stopMusic() method and the MediaPlayer behave on the right way. The problem starts when I'd like to move to another Activity. When I'd like to stop the music it throws me NullPointerExepction for the mediaplayer.stop() . So it looks like the app thinks that I want to stop a never started MediaPlayer. I tried to call the startMusic() method in every onCreate method but the music starts again and again and I'd like to play only one music which don't stop and starts again when I move to another Activity. Is it possible to do that with class or I have to use Service? I hope you can help me to that with class.
BackgroundMusic
public void startMusic() {
mediaPlayer1 = MediaPlayer.create(context, R.raw.zenenegy);
if(palya <= 5 || palya > 15){
mediaPlayer1.start();
mediaPlayer1.setVolume(0.2f, 0.2f);
mediaPlayer1.setLooping(true);
play = true;
}
}
public void stopMusic(){
if(play){
mediaPlayer1.stop();
mediaPlayer1.reset();
mediaPlayer1.release();
mediaPlayer1 = null;
play = false;
}
}
An Activity
BackgroundMusic bm;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fomenu);
bm = new BackgroundMusic(mentes,this);
if(sounds){
bm.startMusic();
}
}
#Override
protected void onPause() {
if(sounds){
bm.stopMusic();
}
super.onPause();
}
If I set the mediaplayer to static in the BackgroundMusic it works perfectly.
I am able to play an mp3 file using android's MediaPlayer object. But I would like to play between a range of milliseconds for example between 30000 ms to 40000 ms ( 10 seconds only ). How can I achieve this?
Currently the following code is what I have,
private MediaPlayer mPlayer;
public void play() {
try {
mPlayer = MediaPlayer.create(getApplicationContext(), R.raw.mp3_file);
if (mPlayer != null) {
int currentPosition = mPlayer.getCurrentPosition();
if (currentPosition + 30000 <= mPlayer.getDuration()) {
mPlayer.seekTo(currentPosition + 30000);
} else {
mPlayer.seekTo(mPlayer.getDuration());
}
mPlayer.start();
}
}
catch(Exception e) {
}
}
Any help is greatly appreciated. Thank you!
You can use the method:
public int getCurrentPosition ()
to obtain the current time in milSeconds maybe inside a Handler that runs every 1000 milSeconds and tests to see:
if(mPlayer.getCurrentPosition() >= (mPlayer.getDuration + 40000));
Dont forget to release the media file when you're done using it:
public void release();
mPlayer.release();
Releases resources associated with this MediaPlayer object. It is
considered good practice to call this method when you're done using
the MediaPlayer. In particular, whenever an Activity of an application
is paused (its onPause() method is called), or stopped (its onStop()
method is called), this method should be invoked to release the
MediaPlayer object, unless the application has a special need to keep
the object around. In addition to unnecessary resources (such as
memory and instances of codecs) being held, failure to call this
method immediately if a MediaPlayer object is no longer needed may
also lead to continuous battery consumption for mobile devices, and
playback failure for other applications if no multiple instances of
the same codec are supported on a device. Even if multiple instances
of the same codec are supported, some performance degradation may be
expected when unnecessary multiple instances are used at the same
time.
The best approach is to use a Handler to time the stopping of the playback. Start the player and then use the Handler's postDelayed to schedule the execution of a Runnable that will stop the player. You should also start the player only after the initial seek completes. Something like this:
public class PlayWord extends Activity implements MediaPlayer.OnSeekCompleteListener {
Handler mHandler;
MediaPlayer mPlayer;
int mStartTime = 6889;
int mEndTime = 7254;
final Runnable mStopAction = new Runnable() {
#Override
public void run() {
mPlayer.stop();
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final TextView tv = new TextView(this);
tv.setText("Playing...");
setContentView(tv);
mHandler = new Handler();
mPlayer = MediaPlayer.create(this, R.raw.nicholas);
mPlayer.setOnSeekCompleteListener(this);
mPlayer.seekTo(mStartTime);
}
#Override
public void onDestroy() {
mPlayer.release();
}
#Override
public void onSeekComplete (MediaPlayer mp) {
mPlayer.start();
mHandler.postDelayed(mStopAction, mEndTime - mStartTime);
}
}
Note also that the MediaPlayer.create method you are using returns a MediaPlayer that has already been prepared and prepare should not be called again like you are doing in your code.on the screen. I also added a call to release() when the activity exits.
Also, if you want to update the UI when the seek completes, be aware that this method is usually called from a non-UI thread. You will have to use the handler to post any UI-related actions.
I'm copied this from: Android: How to stop media (mp3) in playing when specific milliseconds come?
I am using MediaController.MediaPlayerControl in order to display a MediaController at the bottom of my Custom View but I can't get it to work properly. When I play music for first time then there should be pause button visible but instead there is play and when I press that button then the music is paused correctly and state remains the same and after that its working properly. Also when I play next song, the old MediaController widget gets overlapped with the new one. And sometimes the progress/seek bar doesn't refresh while the music is playing. It just updates itself when something on the MediaController is pressed (Play/Pause, forward, etc).
I found these questions similar to mine but I don't think the answers they got will solve my problem.
Android mediacontroller Play Pause controls not refresh properly
Android MediaController seekbar not refreshing
Android VideoView Playback Controls Show "Play" Initially Instead of "Pause" Even Though File is Already Playing
This is how I initialize the controller:
private void setController()
{
controller = new MusicController(this);
controller.setPrevNextListeners(new View.OnClickListener() {
#Override
public void onClick(View v) {
playNext();
}
}, new View.OnClickListener() {
#Override
public void onClick(View v) {
playPrev();
}
});
controller.setMediaPlayer(this);
controller.setAnchorView(findViewById(R.id.song_list));
controller.setEnabled(true);
}
This is how I show controller:
public void playMusic()
{
musicSrv.playSong(); //Play song in a service
setController();
controller.show(0);
controller.requestFocus();
}
I had exactly this problem. Don't know if you still need help, but I thought I'd post anyway. For posterity, are you following this tutorial?
First, the easy problem: you're getting multiple instances of your controls because of repeated calls to setController(). Change the first line of your function to:
if (controller == null) controller = new MusicController(this);
With regards to the play button malfunctioning, I believe it's because you're showing it before the music player has been prepared (disclaimer: I'm a newbie to Android myself, and the following are the things I've found to have worked).
Set up a broadcast from your music-playing service to notify your music-controlling activity when the musicplayer has been prepared. Append the following function in your music-playing service to broadcast intent:
#Override
public void onPrepared(MusicPlayer player) {
// Do some other stuff...
// Broadcast intent to activity to let it know the media player has been prepared
Intent onPreparedIntent = new Intent("MEDIA_PLAYER_PREPARED");
LocalBroadcastManager.getInstance(this).sendBroadcast(onPreparedIntent);
}
Set up a broadcast receiver in your music-controlling activity to receive the intent broadcast by your service. Add the following class to your activity:
// Broadcast receiver to determine when music player has been prepared
private BroadcastReceiver onPrepareReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context c, Intent i) {
// When music player has been prepared, show controller
controller.show(0);
}
};
Register your receiver in your activity's onResume() method:
// Set up receiver for media player onPrepared broadcast
LocalBroadcastManager.getInstance(this).registerReceiver(onPrepareReceiver,
new IntentFilter("MEDIA_PLAYER_PREPARED"));
Depending on the structure of your code, you'll have to do some general tidying up. In my code, I've only called setController() twice: from the onCreate() and onResume() methods in my activity. I also only call controller.show(0) from my broadcast receiver, and my onResume() method.
I have 3 activities. I want to play one background music to all this activity. I made this possible by. Doing this.
In activity 1:
bgmp = MediaPlayer.create(this, R.raw.menu);
bgmp.setLooping(true);
bgmp.start();
This will make my music play up to the 3rd acitivity. At activity three. I need to stop this background music because another background music will be played when I go to the 4th activity. How can I stop the music at the 3rd acitivity that was created at the 1st activity. Any ideas? Thanks!
Define Method in common class with require parameters and use that Method in your activities.
public class CommonMethod {
public static MediaPlayer player;
public static void SoundPlayer(Context ctx,int raw_id){
player = MediaPlayer.create(ctx, raw_id);
player.setLooping(false); // Set looping
player.setVolume(100, 100);
//player.release();
player.start();
}
}
Within in your third activity, code for stop media.
CommonMethod.player.stop();
Create a service to play sound and move all your player code to service.
After that bind your activity to this service and control the music player for (play next, back, pause, stop etc.) features.
Make a singleton class and add you music playing code into it for stopping and starting and use that singleton class in all your 3 activities for eg:
public class MusicManager {
private static MusicManager refrence = null;
public static MusicManager getInstance(){
if(refrence == null){
refrence = new MusicManager ();
}
return refrence;
}
}
add a public method to this singleton class to start and stop music like
public void initalizeMediaPlayer(Context context, int musicId){
// add initalization of media player in it and loop it
}
public void startPlaying(){
// add code to start playing music
}
public void stopPlaying(){
// add code to stop playing music
}
And for making use this class use like this
MusicManager.getInstance().initalizeMediaPlayer(this, R.raw.menu); // to initalize of media player
MusicManager.getInstance().startPlaying();// to start playing music
MusicManager.getInstance().stopPlaying(); // to stop playing music
Let me know if this helps you.
Mean while you can also use service to perform this task as service runs in background . you can start service and stop service any time in your code
You Should Start Service which runs in background and write code for playing music in the service..
All you have to do is add this piece of code to your intent to the last activity:
yourMediaPlayer.pause()
So the whole code would be :
yourMediaPlayer.pause();
Intent i ...
startActivity(i);
Just put player.stop() function inside button which takes you to next activity:
example: #Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
player.stop();
Intent i=new Intent(iotmain.this,MainActivity.class);
startActivity(i);
Toast.makeText(getBaseContext(),"Chatting mode ON",Toast.LENGTH_SHORT).show();
}
i am using VideoView and seek bar but when i seekTo(..) on desired position through seekBar it play video from starting.
i trying this code:
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
mVideoView.seekTo(progress);
}
As Reno mentioned, you have to wait for the seeking to complete.
VideoView does not have a OnSeekCompleteListener() but you can access the MediaPlayer from the onPrepared method of the VideoView and then set the OnSeekCompleteListener, like this :
mVideoView.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.setOnSeekCompleteListener(new OnSeekCompleteListener() {
#Override
public void onSeekComplete(MediaPlayer mp) {
//TODO: Your code here
}
});
}
});
The call to VideoView.seekTo() is a wrapper around MediaPlayer.seekTo(). This function returns almost immediately even though the actual seeking is still being performed. Therefore you want to wait for seeking to complete via MediaPlayer.OnSeekCompleteListener.
However, as Reno mentioned, the standard VideoView does not support OnSeekCompleteListener.
But you can copy and locally customize the VideoView class to add this support yourself.
First, start with a copy of VideoView.java. Or you can clone the entire frameworks/base repo but warning it is over 1 gig of data to download.
Copy VideoView.java into your Eclipse Android project and it will start building but fail. Here's what I did to get it to compile:
Update the package statement to match your project.
Comment out the references to MetaData. The fix for this is on my todo list. These need to be replaced with calls to MediaMetadataRetriever.
Replace mContext with calls to getBaseContext()
Now you are ready to add the code for OnSeekCompleteListener. The implementation is similar to the other listeners, i.e OnCompletionListener.
public class VideoView extends SurfaceView
implements MediaPlayerControl {
// The client's listener which is the notification callback.
private OnSeekCompleteListener mOnSeekCompleteListener;
// Set up MediaPlayer to forward notifications to client.
private MediaPlayer.OnSeekCompleteListener mSeekCompleteListener =
new MediaPlayer.OnSeekCompleteListener() {
public void onSeekComplete(MediaPlayer mp) {
if (mOnCompletionListener != null) {
mOnCompletionListener.onCompletion(mMediaPlayer);
}
}
};
// API for client to set their listener.
public void setOnSeekCompleteListener(OnSeekCompleteListener l)
{
mOnSeekCompleteListener = l;
}
}
Finally, update your own code:
Update references to android.widget.VideoView to use your customized VideoView.
Implement a listener and set it via by calling setOnSeekCompleteListener().
Your code now receives notifications when the seek has really completed and it can then perform subsequent seeks.
You have to wait for the seeking to complete, unfortunately VideoView does not have a OnSeekCompleteListener() (why Google? -_-)
use my method works like charm
Take mediaPlayer
MediaPlayer mediaPlayer;
init mediaPlayer
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mediaPlayer = mp;
}
});
use seekTo method like this
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mediaPlayer.seekTo((int) mStartPosition, MediaPlayer.SEEK_CLOSEST);
} else {
mediaPlayer.seekTo((int) mStartPosition);
}
You should use
mVideoView.seekTo(progress, SEEK_CLOSEST)