Maybe the title isn't explicit enough, let me explain.
I am working on an already existing code, Java for Android app. The actual app have a mediaplayer playing audio stream, with only a play/pause button in the layout.
The played is initialized and used in an activity.
When the phone is locked, the stream continues to play but there is no notification displayed with the next previous etc buttons.
Using this tutorial i managed to dispay the notification on lock screen and on notification area when i call this service from the activity:
Intent intent = new Intent(getApplicationContext(), MediaPlayerService.class);
intent.setAction(MediaPlayerService.ACTION_PAUSE);
startService(intent);
But it's obviously not working well as the already existing session is not linked to the new created controller on the notification.
So i'm wondering if it's better to:
Use the new service i created and try to link it to existing session
Dish the previous mediaplayer from the activity and handle all the media things in service
Keep all the media handling in the activity
I'm not very familiar with Medias handling in Android.
Here is some preview of the actual code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_exercices);
setFinishOnTouchOutside(false);
mContext = this;
// Init of MediaSession
//mSession = new MediaSessionCompat(this, "MusicService");
//mSession.setCallback(new MediaSessionCallback());
//mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS | MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
//setSessionToken(mSession.getSessionToken());
mAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
mRemoteControlResponder = new ComponentName(getPackageName(),
RemoteControlReceiver.class.getName());
mStateBuilder = new PlaybackStateCompat.Builder()
.setActions(
PlaybackStateCompat.ACTION_PLAY |
PlaybackStateCompat.ACTION_PLAY_PAUSE);
initializeViews();
initializeActions();
}
public void initializeActions() {
recyclerExercisesView.setLayoutManager(new LinearLayoutManager(mContext));
pAdapterExercise = new ExercisesPlayerAdapter(mContext, allExercisesList, isGuest, new ExercisesPlayerAdapter.RecyclerItemClickListener() {
#Override
public void onClickListener(Exercise exercice, int position) {
//Toast.makeText(DetailsSceanceActivity.this, exercice.getPath(), Toast.LENGTH_SHORT).show();
iv_play.setEnabled(true);
seekBar_progress.setEnabled(true);
if (!chronoLaunch && firstLaunch) {
startChrono();
startSensors();
}
firstLaunch = false;
changeSelectedExercice(position);
prepareExercise(exercice);
}
});
recyclerExercisesView.setAdapter(pAdapterExercise);
mMediaController = new MediaController(this);
Intent intent = new Intent(getApplicationContext(), MediaPlayerService.class);
intent.setAction(MediaPlayerService.ACTION_PAUSE);
startService(intent);
// inint mediaplayer
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
// play song
togglePlay(mp);
//mMediaController.setMediaPlayer(this);
}
});
}
I also saw few samples with MediaSessionCompat. Better use MediaSession or MediaSessionCompat?
Thanks
Related
I have a MediaPlayerService, currently started when the Play/Pause Button on a ListView item is clicked. See code below (CustomListAdapter):
Intent intent = new Intent(v.getContext(),MediaPlayerService.class);
intent.putExtra("StreamLink",audio);
activity.startService(intent);
When this service is started by the code above I want to create a Notification with a Play/Stop button. The user should be able to get out of the app, be able to stop Media Playback e.g. player.stop() and start player.start(). Also when the Notification is clicked it should return the user to the MainActivity.
The code for my MediaPlayerService.java:
public class MediaPlayerService extends Service implements MediaPlayer.OnPreparedListener {
MediaPlayer mMediaPlayer = null;
public String audioStreamLink;
public int onStartCommand(Intent intent, int flags, int startId) {
// Get the Audio Streaming Link from the parsed JSON in the Main Activity
audioStreamLink = intent.getStringExtra("StreamLink");
// Instantiate MediaPlayer, set the Audio Type and acquire a wakelock, set the Media Player Data Source and Prepare.
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mMediaPlayer.setDataSource(audioStreamLink);
} catch (IOException e) {
e.printStackTrace();
}
mMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.prepareAsync();
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
/** Called when MediaPlayer is ready */
#Override
public void onPrepared(MediaPlayer player) {
player.start();
}
#Override
public void onDestroy() {
mMediaPlayer.stop();
mMediaPlayer.reset();
if (mMediaPlayer != null) mMediaPlayer.release();
}
}
The process of getting a notification is completely documented down there in the documents, for example, see this.
To help you go through all this huge documentation these are the points :
You need to create the custom notification using a NotificationCompat.Builder
A typical music player service would start the notification using startForeground()
To add clickable buttons to the notification use addAction() when building the notifications.
Actions in Notifications are defined by PendingIntent, its a kind of normal Intent when it comes to responding to it.
When a button on the notification is clicked, the onStartCommand() is triggered with the intent you specified for that button (if you configure the intent correctly).
Each button's intent should have a different action so that you can identify the intent when it is received.
Inside the onStartCommand() you can play/pause and do other operations based on this intent's action.
Some reference I would suggest you to read :
https://developer.android.com/guide/topics/ui/notifiers/notifications.html
https://developer.android.com/guide/topics/ui/notifiers/notifications.html#Updating
https://developer.android.com/reference/android/app/Service.html#startForeground(int,android.app.Notification)
Things would have been a bit different if you were using a MediaSession to play the media.
I want to implement volume change as seen in Youtube app while casting, like if app is in background or on lock screen
Like this
private void createSession() {
ComponentName receiver = new ComponentName(getPackageName(), RemoteReceiver.class.getName());
mediaSession = new MediaSessionCompat(this, "PlayerService", receiver, null);
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
mediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_PLAYING, 0, 1f)
.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE)
.build());
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
audioManager.requestAudioFocus(new AudioManager.OnAudioFocusChangeListener() {
#Override
public void onAudioFocusChange(int focusChange) {
// Ignore
}
}, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
mediaSession.setActive(true);
mediaRouter = MediaRouter.getInstance(this);
mediaRouter.setMediaSessionCompat(mediaSession);
}
Now I get the slider just like Image above and it responds to volume buttons, but I dont receive change in my broadcast receiver.
All you have to do is create a MediaSessionCompat with a VolumeProviderCompat.
// Here is a volume provider which sets the volume of a remote route.
// Extend VolumeProviderCompat with your own implementation.
public static class RemoteVolume extends VolumeProviderCompat {
public RemoteVolume(MediaRouter.RouteInfo routeInfo) {
super(VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE, STEPS, 0);
this.stepSize = routeInfo.getVolumeMax() / STEPS;
this.routeInfo = routeInfo;
}
#Override
public void onSetVolumeTo(int volume) {
routeInfo.requestSetVolume(volume * stepSize);
setCurrentVolume(volume);
}
#Override
public void onAdjustVolume(int delta) {
int newVolume = getCurrentVolume() + delta;
routeInfo.requestSetVolume(newVolume * stepSize);
setCurrentVolume(newVolume);
}
}
Then, connect the VolumeProviderCompat to your MediaSessionCompat:
MediaSessionCompat session = new MediaSessionCompat(context, TAG);
// might need some of these flags
session.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS |
MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS);
// the volume buttons are routed to this session when it is
// active and currently playing
session.setPlaybackState(new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_PLAYING, 0, 1.0f)
.build());
session.setActive(true);
// The media router tries to bind its own VolumeProvider which kinda
// works. We need to unbind the one provided and put ours in.
router.setMediaSessionCompat(session);
session.setPlaybackToRemote(new RemoteVolume(myRemoteRoute));
This question has been asked a few times, but none of the answers have helped me solve my problem so I'm posting my version of it.
I'm creating an app that plays a list of songs through a service. The problem is that I got a null exception error from the mediaPlayer after I rotate the device. As you can see below, I first start and then bind to my service in the onResume method. Likewise, I unbind and stop the service in the onDestroy method.
protected void onResume() {
if (playIntent == null) {
playIntent = new Intent(MainActivity.this, MediaService.class);
// if (n < 0) {
startService(playIntent);
bindService(playIntent, mediaConnection, Context.BIND_AUTO_CREATE);
Log.d("Check", "Started Service");
// }
}
super.onResume();
}
In my service, I set up the mediaPlayer in the service's onCreate method as below. I have a few things in the onStartCommand method (like creating a notification to show in the action bar). I also return Start_sticky in onStartCommand method.
Unfortunately, like I said, when I rotate the device, I get a null exception from the mediaPlayer.
Please help; I've been trying to fix this for days.
static private MediaPlayer player;
private final IBinder musicBind = new MediaBinder();
Notification notification;
private int playbackDuration;
static Uri paths[][] = new Uri[MainActivity.NUMBER_OF_ARTISTS][MainActivity.NUMBER_OF_TRACKS];
public void onCreate() {
// create the service
super.onCreate();
player = new MediaPlayer();
player.reset();
player.setLooping(true);
initMediaPlayer();
Log.d("Check", "In Service's OnCreate method");
I am working on a music player
The logic is like this:
First, I click on the play button , if there is music playing, stop the service , otherwise , start it.
Play / Pause Button:
playM.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
AudioManager manager = (AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE);
if (!manager.isMusicActive()) {
playM.setText("Pause");
Intent svc=new Intent(getContext(), Music.class);
svc.putExtra("uri", tt1.getText().toString());
getContext().startService(svc);
} else {
playM.setText("Play");
//if (mPlayer != null && mPlayer.isPlaying()) {
Intent svc=new Intent(getContext(), Music.class);
getContext().stopService(svc);
//}
}
}
});
Service:
public int onStartCommand(Intent intent, int flags, int startId) {
path = (String) intent.getExtras().get("uri");
Uri uriMusic = Uri.parse(path);
player = MediaPlayer.create(this, uriMusic);
player.start();
player.setLooping(true); // Set looping
return 1;
}
#Override
public void onDestroy() {
player.stop();
player.release();
}
The problem is, if the music is playing by another apps, my music player will crash. But I can not find any way to track the service status. For example, if I play the music, close the app , the music is still playing , but when I open the app again , how to know the specific service (play music which is fire by my app only, in this case) is running? Thanks
In My Application im using following code to play audio file
Uri data = Uri.parse("file:/" + songnameandpath);
intent.setDataAndType(data, "audio/*");
PackageManager packageManager = getActivity()
.getPackageManager();
List<ResolveInfo> activities = packageManager
.queryIntentActivities(intent, 0);
boolean isIntentSafe = activities.size() > 0;
if (isIntentSafe) {
startActivity(intent);
so now when user clicks on back button audio get stopped what if i want to play audio even if the user presses back button on activity and moreover it has to play in background exactly how audio will in mobiles.
Sample code will helps me a lot.
Thanks in advance
Have you tried working with media player?
here is the code that worked for me, just delete the on pause/destroy methods or redefine them and you will have sound playing even when the user presses back..
public class MainActivity extends Activity {
private MediaPlayer mp;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mp= MediaPlayer.create (this, R.raw.sound); // sound is for example your mp3 song
mp.start ();
}
protected void onDestroy() {
super.onDestroy();
mp.release();
}
protected void onPause() {
super.onPause();
mp.pause();
}
protected void onResume() {
super.onResume();
mp.start();
}
protected void onStart() {
super.onStart();
}
}
update
The MediaPlayer will continue playing file even after the activity is finished unless you explicitly stop it by stop function