In my android app that I am working on, I have implemented MediaPlayer service class (PlayService.java) which will play live radio audio stream from a remote source. When a service runs in the foreground, it displays a notification with play/pause media transport control so that the user can handle media player actions from there also. I am successful in doing all so but the only problem I face is that when the user clear that notification from notification area the notification gets dismissed but the service won't stop. I have research alot but couldn't find any proper solution.
My working code for MediaPlayer Service class is:
public class PlayService extends Service implements MediaPlayer.OnCompletionListener,MediaPlayer.OnPreparedListener,
MediaPlayer.OnErrorListener,MediaPlayer.OnSeekCompleteListener,MediaPlayer.OnInfoListener,
MediaPlayer.OnBufferingUpdateListener,AudioManager.OnAudioFocusChangeListener {
private AudioManager audioManager;
private MediaPlayer mediaPlayer = new MediaPlayer();
private String sentAudioLink="";
//Used to pause/resume MediaPlayer
private int resumePosition;
//Handle notification in system tray
private NotificationCompat.Builder builder;
private NotificationManager notificationManager;
private int notification_id;
private RemoteViews remoteViews;
public static final String ACTION_PLAY = "com.example.ACTION_PLAY";
public static final String ACTION_PAUSE = "com.example.ACTION_PAUSE";
public static final String ACTION_STOP = "com.example.ACTION_STOP";
//MediaSession
private MediaSessionManager mediaSessionManager;
private MediaSessionCompat mediaSession;
private MediaControllerCompat.TransportControls transportControls;
//AudioPlayer notification ID
private static final int NOTIFICATION_ID = 101;
#Override
public void onCreate() {
mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnErrorListener(this);
mediaPlayer.setOnSeekCompleteListener(this);
mediaPlayer.setOnInfoListener(this);
mediaPlayer.setOnBufferingUpdateListener(this);
mediaPlayer.reset();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Bundle bundle = intent.getExtras();
if (bundle != null)
{
sentAudioLink = intent.getExtras().getString("sentAudioLink");
}
mediaPlayer.reset();
//setup the media player data source using the strAudioLink value
if (!mediaPlayer.isPlaying()) {
try {
mediaPlayer.setDataSource(sentAudioLink);
//prepare media player
mediaPlayer.prepareAsync();
} catch (IllegalStateException e) {
Log.e("workingerror1", e.toString());
stopSelf();
} catch (IllegalArgumentException e) {
Log.e("workingerror2", e.toString());
stopSelf();
} catch (IOException e) {
Log.e("workingerror3", e.toString());
stopSelf();
}
buildNotification(PlaybackStatus.PLAYING);
}
//Handle Intent action from MediaSession.TransportControls
handleIncomingActions(intent);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
removeNotification();
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer=null;
}
}
#Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
}
#Override
public void onCompletion(MediaPlayer mp) {
stopMedia();
stopSelf();
buildNotification(PlaybackStatus.PAUSED);
}
public void stopMedia() {
if (mediaPlayer.isPlaying())
mediaPlayer.stop();
}
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
return false;
}
#Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
return false;
}
#Override
public void onPrepared(MediaPlayer mp) {
playMedia();
}
public void playMedia() {
if (!mediaPlayer.isPlaying() && sentAudioLink!="") {
mediaPlayer.start();
}
}
#Override
public void onSeekComplete(MediaPlayer mp) {
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void buildNotification(PlaybackStatus playbackStatus) {
int notificationAction = android.R.drawable.ic_media_pause;//needs to be initialized
PendingIntent play_pauseAction = null;
//Build a new notification according to the current state of the MediaPlayer
if (playbackStatus == PlaybackStatus.PLAYING) {
notificationAction = android.R.drawable.ic_media_pause;
//create the pause action
play_pauseAction = playbackAction(1);
} else if (playbackStatus == PlaybackStatus.PAUSED) {
notificationAction = android.R.drawable.ic_media_play;
//create the play action
play_pauseAction = playbackAction(0);
}
Bitmap largeIcon = BitmapFactory.decodeResource(getResources(),
R.drawable.uow_logo); //replace with your own image
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this,CHANNEL_ID)
.setShowWhen(false)
// Set the Notification style
.setStyle(new MediaStyle()
// Show our playback controls in the compact notification view.
.setShowActionsInCompactView(0)
.setShowCancelButton(true)
.setCancelButtonIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(
this, PlaybackStateCompat.ACTION_STOP)))
// Set the Notification color
.setColor(getResources().getColor(R.color.colorPrimary))
// Set the large and small icons
.setSmallIcon(R.drawable.uow_logo)
.setLargeIcon(largeIcon)
// Set Notification content information
.setContentText("FM Radia - 101.8")
.setContentTitle("University of Wah")
.setOngoing(true)
.setAutoCancel(false)
// Add playback actions
.addAction(notificationAction, "pause", play_pauseAction)
.setDeleteIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(
this, PlaybackStateCompat.ACTION_STOP));
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).notify(NOTIFICATION_ID, notificationBuilder.build());
}
private void removeNotification() {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(NOTIFICATION_ID);
}
private PendingIntent playbackAction(int actionNumber) {
Intent playbackAction = new Intent(this, PlayService.class);
switch (actionNumber) {
case 0:
// Play
playbackAction.setAction(ACTION_PLAY);
return PendingIntent.getService(this, actionNumber, playbackAction, 0);
case 1:
// Pause
playbackAction.setAction(ACTION_PAUSE);
return PendingIntent.getService(this, actionNumber, playbackAction, 0);
default:
break;
}
return null;
}
private void handleIncomingActions(Intent playbackAction)
{
if (playbackAction == null || playbackAction.getAction() == null) return;
String actionString = playbackAction.getAction();
Log.e("actionString",actionString);
if (actionString.equalsIgnoreCase(ACTION_PLAY))
{
//Play the music
}
else if (actionString.equalsIgnoreCase(ACTION_PAUSE))
{
if (mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
buildNotification(PlaybackStatus.PAUSED);
stopSelf();
}
else(actionString.equalsIgnoreCase(ACTION_STOP))
{
if (mediaPlayer != null) {
removeNotification();
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer=null;
}
}
}
}
Related
I use media player in service and activity with a button(play/stop stream).
I'm trying to do such a one thing:
start serice only once when activity starts, and than use UI part to operate with media player in service (start, stop streaming). I'm using for it Service Binder.
But when i click on button to start media player, it causes errors:
E/MediaPlayer: start called in state 1
E/MediaPlayer: error (-38, 0)
Than i added the flag isPrepared to onPrepared() and on play stream button click check the flag. Flag is always false.
It seems that onPrepare() is not called or smth like that. Why? What's wrong?
UPDATED
Activity:
public class MainActivity extends AppCompatActivity {
String url = "http://62.80.190.246:8000/ProstoRadiO128";
Button mPlayPauseButton;
boolean musicPlaying = false;
Intent serviceIntent;
MyService mService;
boolean mBound = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
initListeners();
}
#Override
protected void onStart() {
super.onStart();
serviceIntent = new Intent(this, MyService.class);
serviceIntent.putExtra("url", url);
bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
startService(serviceIntent);
musicPlaying = true;
mPlayPauseButton.setBackgroundResource(R.drawable.pause);
Log.d("", "mConnection: " + mConnection);
}
#Override
protected void onStop() {
super.onStop();
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyService.MyServiceBinder binder = (MyService.MyServiceBinder) service;
mService = binder.getService();
mBound = true;
Log.d("", "in onServiceConnected: mBound = " + mBound);
}
#Override
public void onServiceDisconnected(ComponentName name) {
mBound = false;
}
};
private void initViews() {
mPlayPauseButton = (Button) findViewById(R.id.btn_play_pause);
mPlayPauseButton.setBackgroundResource(R.drawable.play);
}
private void initListeners() {
mPlayPauseButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
playPauseClick();
}
});
}
private void playPauseClick() {
if (musicPlaying == false) { //mBound &&
Log.d("", "mBound: " + mBound);
mService.startStream();
mPlayPauseButton.setBackgroundResource(R.drawable.pause);
musicPlaying = true;
}
else if (musicPlaying == true) { //!mBound
mService.stopStream();
mPlayPauseButton.setBackgroundResource(R.drawable.play);
musicPlaying = false;
}
}
}
UPDATED
Service:
public class MyService extends Service implements MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener{
String TAG = "PlayerService__Log";
String url;
MediaPlayer mediaPlayer;
private final IBinder mBinder = new MyServiceBinder();
boolean isPrepared;
public class MyServiceBinder extends Binder {
MyService getService() {
return MyService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onCreate() {
Log.v(TAG, "Creating Service");
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnCompletionListener(this);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
url = intent.getStringExtra("url");
Log.d(TAG, "url: " + url);
if (!mediaPlayer.isPlaying()) {
try {
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(url);
mediaPlayer.prepareAsync();
} catch (Exception e) {
e.printStackTrace();
Log.d(TAG, e.getClass().getName() + " " + e.getMessage());
}
}
return START_STICKY;
}
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
Log.d(TAG, "media player prepared");
isPrepared = true;
}
#Override
public void onCompletion(MediaPlayer mp) {
Log.d(TAG, "onCompletion");
}
#Override
public void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
mediaPlayer = null;
}
}
public void startStream() {
if (!mediaPlayer.isPlaying() ) { //&& isPrepared == true
mediaPlayer.start();
Log.d(TAG, "media player started");
}
else {
Log.d(TAG, "media player is not prepared");
//isPrepared = false;
}
}
public void stopStream() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
Log.d(TAG, "media player stoped");
}
}
}
You forgot to start the service. Call:
startService(serviceIntent);
Please read this as you will need to stop the service too.
and for pausing, rather than stop, call:
mediaPlayer.pause();
Familiarise yourself with the state diagram and invalid states in the docs.
onPrepared() is called when the player is successfully prepared/initialised.
But as the Error is indicating, something goes wrong during this phase and (probably) therfore onPrepared never gets called.
You could try to override onError, to get notified like this:
#Override
public boolean onError(MediaPlayer mediaPlayer, int what, int why) {
Log.e(TAG, "onError");
setPlayerState(PlayerState.ERROR);
if (MediaPlayer.MEDIA_ERROR_UNKNOWN == what) {
Log.d(TAG, "MEDIA_ERROR_UNKNOWN");
if (MediaPlayer.MEDIA_ERROR_IO == why) {
Log.e(TAG, "MEDIA_ERROR_IO");
if (this.playbackPosition > 0) { //we could play this video in the past, but cannot resume. start all over again.
Log.e(TAG, "Probably we requested a content range, but server didn't support that. (responded with 200), restarting!");
this.playbackPosition = 0;
start(this.playbackPosition);
} else {
callbacks.onUnrecoverableError(what, why);
}
}
if (MediaPlayer.MEDIA_ERROR_MALFORMED == why) {
Log.e(TAG, "MEDIA_ERROR_MALFORMED");
callbacks.onUnrecoverableError(what, why);
}
if (MediaPlayer.MEDIA_ERROR_UNSUPPORTED == why) {
Log.e(TAG, "MEDIA_ERROR_UNSUPPORTED");
callbacks.onUnrecoverableError(what, why);
}
if (MediaPlayer.MEDIA_ERROR_TIMED_OUT == why) {
Log.e(TAG, "MEDIA_ERROR_TIMED_OUT");
callbacks.onUnrecoverableError(what, why);
}
} else if (MediaPlayer.MEDIA_ERROR_SERVER_DIED == what) {
Log.e(TAG, "MEDIA_ERROR_SERVER_DIED");
callbacks.onUnrecoverableError(what, why);
}
return true;
}
When user tap play button from notification, it should play music and icon of play should be changed to Pause. I am able to get play button in my notification bar. but can't provide them control. And also if user close the app. music should be play in background.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.play);
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
btn.setOnClickListener(pausePlay);
}
private OnClickListener pausePlay = new OnClickListener() {
#Override
public void onClick(View v) {
sendNotify();
if (!playPause) {
btn.setBackgroundResource(R.drawable.pause);
if (intialStage)
new Player().execute("");
else {
if (!mediaPlayer.isPlaying())
mediaPlayer.start();
}
playPause = true;
} else {
btn.setBackgroundResource(R.drawable.play);
if (mediaPlayer.isPlaying())
mediaPlayer.pause();
playPause = false;
}
}
private void sendNotify() {
Context context = getApplicationContext();
Intent playOrpause = new Intent(MainActivity.this, MainActivity.class);
playOrpause.putExtra("play", true);
PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 0, playOrpause, Intent.FLAG_ACTIVITY_NEW_TASK);
Intent sample = new Intent(Intent.ACTION_VIEW, Uri.parse(""));
PendingIntent pendingnihal = PendingIntent.getActivity(MainActivity.this, 0, sample, Intent.FLAG_ACTIVITY_NEW_TASK);
myNotification = new Notification.Builder(context).setContentTitle("Playing Song").setContentText("Media Started")
.setTicker("Music Player")
.setSmallIcon(R.drawable.ic_launcher)
.setWhen(System.currentTimeMillis())
.setContentIntent(pendingIntent)
.setDefaults(Notification.DEFAULT_SOUND)
.setDefaults(Notification.DEFAULT_LIGHTS)
.setAutoCancel(false)
.setSmallIcon(R.drawable.ic_launcher)
.addAction(R.drawable.play, "", pendingIntent)
.addAction(R.drawable.pause, "", pendingnihal)
.build();
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(MY_NOTIFICATION_ID, myNotification);
}
};
class Player extends AsyncTask<String, Void, Boolean> {
private ProgressDialog progress;
#Override
protected Boolean doInBackground(String... params) {
Boolean prepared;
try {
validation();
mediaPlayer.setDataSource(params[0]);
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
intialStage = true;
playPause = false;
btn.setBackgroundResource(R.drawable.ic_launcher);
mediaPlayer.stop();
mediaPlayer.reset();
}
});
mediaPlayer.prepare();
prepared = true;
} catch (IllegalArgumentException e) {
Log.d("IllegarArgument", e.getMessage());
prepared = false;
e.printStackTrace();
} catch (SecurityException e) {
prepared = false;
e.printStackTrace();
} catch (IllegalStateException e) {
prepared = false;
e.printStackTrace();
} catch (IOException e) {
prepared = false;
e.printStackTrace();
}
return prepared;
}
private void validation() {
Intent intent = getIntent();
boolean msg = intent.getExtras().getBoolean("play");
if(msg){
mediaPlayer.start();
}
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if (progress.isShowing()) {
progress.cancel();
}
Log.d("Prepared", "//" + result);
mediaPlayer.start();
intialStage = false;
}
public Player() {
progress = new ProgressDialog(MainActivity.this);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
this.progress.setMessage("Buffering...");
this.progress.show();
}
}
#Override
protected void onPause() {
super.onPause();
if (mediaPlayer != null) {
mediaPlayer.reset();
mediaPlayer.release();
mediaPlayer = null;
}
}
public class NotifyServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
int rqs = arg1.getIntExtra("RQS", 0);
if (rqs == RQS_STOP_SERVICE) {
// stopSelf();
}
}
}
}
You can't directly do that. But you can use RemoteViews.setOnClickPendingIntent(int viewId, PendingIntent pendingIntent).
setOnClickPendingIntent(int viewId, PendingIntent pendingIntent) Equivalent to calling setOnClickListener(android.view.View.OnClickListener) to launch the provided PendingIntent.
please check this
I building a Radio Streaming app and i am having difficulties sending my MediaPlayer object from my service to to a fragment. Below is my Service and my Fragment code. When i try to run the code it's always crashing
public class StreamService extends Service implements
MediaPlayer.OnCompletionListener,
MediaPlayer.OnPreparedListener,
MediaPlayer.OnErrorListener,
MediaPlayer.OnBufferingUpdateListener {
private static final int NOTIFICATION_ID = 1;
private PhoneStateListener phoneStateListener;
private TelephonyManager telephonyManager;
private boolean isPausedInCall = false;
private NotificationCompat.Builder builder;
//intent
private Intent bufferIntent;
public static final MediaPlayer mediaPlayer = new MediaPlayer();
ScheduledExecutorService scheduleTaskExecutor, reminderTaskExecutor;
private ScheduleModel scheduleModel;
private int currentHour;
private String currentDay, notificationTitle;
private final IBinder mBinder = new LocalBinder();
#Override
public void onCreate() {
super.onCreate();
bufferIntent = new Intent(BROADCAST_BUFFER);
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnErrorListener(this);
mediaPlayer.setOnBufferingUpdateListener(this);
mediaPlayer.reset();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
reminderTaskExecutor = Executors.newScheduledThreadPool(5);
reminderTaskExecutor.scheduleAtFixedRate(new Runnable() {
public void run() {
//initNotification();
}
}, 0, 1, TimeUnit.MINUTES);
telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
phoneStateListener = new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_OFFHOOK:
case TelephonyManager.CALL_STATE_RINGING:
if (mediaPlayer != null) {
pauseMedia();
isPausedInCall = true;
}
break;
case TelephonyManager.CALL_STATE_IDLE:
if (mediaPlayer != null) {
if (isPausedInCall) {
isPausedInCall = false;
playMedia();
}
}
break;
}
}
};
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
initNotification();
mediaPlayer.reset();
/**
* play media
*/
if (!mediaPlayer.isPlaying()) {
try {
mediaPlayer.setDataSource(URL_STREAM);
// sent to UI radio is buffer
sendBufferingBroadcast();
mediaPlayer.prepareAsync();
} catch (IllegalArgumentException e) {
Log.d("error", e.getMessage());
} catch (IllegalStateException e) {
Log.d("error", e.getMessage());
} catch (IOException e) {
Log.d("error", e.getMessage());
}
}
return START_STICKY;
}
public class LocalBinder extends Binder {
public StreamService getService() {
// Return this instance of LocalService so clients can call public methods
return StreamService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onBufferingUpdate(MediaPlayer mediaPlayer, int i) {
}
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
stopMedia();
stopSelf();
}
#Override
public boolean onError(MediaPlayer mediaPlayer, int what, int extra) {
switch (what) {
case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
Toast.makeText(this, "Error not valid playback", Toast.LENGTH_SHORT).show();
break;
case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
Toast.makeText(this, "Error server died", Toast.LENGTH_SHORT).show();
break;
case MediaPlayer.MEDIA_ERROR_UNKNOWN:
Toast.makeText(this, "Error occurred, please try again", Toast.LENGTH_SHORT).show();
break;
}
return false;
}
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
// sent to UI, audio has buffered
sendBufferCompleteBroadcast();
playMedia();
}
private void pauseMedia() {
if (mediaPlayer.isPlaying())
mediaPlayer.pause();
}
private void playMedia() {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
private void stopMedia() {
if (mediaPlayer.isPlaying())
mediaPlayer.stop();
}
/**
* sent buffering
*/
private void sendBufferingBroadcast() {
bufferIntent.putExtra("buffering", "1");
sendBroadcast(bufferIntent);
}
/**
* sent buffering complete
*/
private void sendBufferCompleteBroadcast() {
bufferIntent.putExtra("buffering", "0");
sendBroadcast(bufferIntent);
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d("tag", "remove notification");
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
}
if (phoneStateListener != null) {
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
}
cancelNotification();
}
}
My Fragment, code crashed on line mVisualizerView.link(StreamService.mediaPlayer);
private void startVisualizerView(){
mVisualizerView = (VisualizerView) getView().findViewById(R.id.visualizerView);
mVisualizerView.link(StreamService.mediaPlayer);
// Start with just line renderer
addLineRenderer();
}
private void startVisualizerView(){
mVisualizerView = (VisualizerView) getView().findViewById(R.id.visualizerView);
mVisualizerView.link(StreamService.mediaPlayer);
// Start with just line renderer
addLineRenderer();
}
private void startStreaming(Context context) {
stopStreaming();
try {
getActivity().startService(serviceIntent);
Toast.makeText(context, "Enjoy #Hashtag Radio...", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
}
}
private void stopStreaming() {
try {
getActivity().stopService(serviceIntent);
// reset streaming tag
isStreaming = false;
Utils.setDataBooleanToSP(getActivity(), Utils.IS_STREAM, false);
} catch (Exception e) {
}
}
private void startStreaming(Context context) {
stopStreaming();
try {
getActivity().startService(serviceIntent);
startVisualizerView();
Toast.makeText(context, "Enjoy #Hashtag Radio...", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
StreamService.LocalBinder binder = (StreamService.LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
I'm trying to create a Service that will play a music in the background in Android.
But I get an NPE while the service is starting.
Could anyone tell me what I'm doing wrong?
Log cat:
12-28 12:07:19.602: W/System.err(3768): java.lang.IllegalStateException
12-28 12:07:19.722: W/System.err(3768): at android.media.MediaPlayer.prepare(Native Method)
12-28 12:07:19.722: W/System.err(3768): at com.darkovski.quran.myPlayService.playMedia(myPlayService.java:413)
12-28 12:07:19.722: W/System.err(3768): at com.darkovski.quran.myPlayService.onPrepared(myPlayService.java:390)
12-28 12:07:19.722: W/System.err(3768): at android.media.MediaPlayer$EventHandler.handleMessage(MediaPlayer.java:1523)
12-28 12:07:19.722: W/System.err(3768): at android.os.Handler.dispatchMessage(Handler.java:99)
12-28 12:07:19.722: W/System.err(3768): at android.os.Looper.loop(Looper.java:137)
12-28 12:07:19.722: W/System.err(3768): at android.app.ActivityThread.main(ActivityThread.java:4441)
12-28 12:07:19.722: W/System.err(3768): at java.lang.reflect.Method.invokeNative(Native Method)
12-28 12:07:19.722: W/System.err(3768): at java.lang.reflect.Method.invoke(Method.java:511)
12-28 12:07:19.722: W/System.err(3768): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
12-28 12:07:19.722: W/System.err(3768): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
12-28 12:07:19.722: W/System.err(3768): at dalvik.system.NativeStart.main(Native Method)
My code:
public class myPlayService extends Service implements OnCompletionListener,
OnPreparedListener, OnErrorListener, OnSeekCompleteListener,
OnInfoListener, OnBufferingUpdateListener {
private static final String TAG = "TELSERVICE";
private MediaPlayer mediaPlayer = new MediaPlayer();
// songs
private ArrayList<Songs> songs;
private int position;
// Set up the notification ID
private static final int NOTIFICATION_ID = 1;
private boolean isPausedInCall = false;
private PhoneStateListener phoneStateListener;
private TelephonyManager telephonyManager;
// ---Variables for seekbar processing---
String sntSeekPos;
int intSeekPos;
int mediaPosition;
int mediaMax;
// Intent intent;
private final Handler handler = new Handler();
private static int songEnded;
public static final String BROADCAST_ACTION = "com.darkovski.quran.seekprogress";
// Set up broadcast identifier and intent
public static final String BROADCAST_BUFFER = "com.darkovski.quran.broadcastbuffer";
Intent bufferIntent;
Intent seekIntent;
// Declare headsetSwitch variable
private int headsetSwitch = 1;
// OnCreate
#Override
public void onCreate() {
Log.v(TAG, "Creating Service");
// android.os.Debug.waitForDebugger();
// Instantiate bufferIntent to communicate with Activity for progress
// dialogue
songs = new ArrayList<Songs>();
bufferIntent = new Intent(BROADCAST_BUFFER);
// ---Set up intent for seekbar broadcast ---
seekIntent = new Intent(BROADCAST_ACTION);
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnErrorListener(this);
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnBufferingUpdateListener(this);
mediaPlayer.setOnSeekCompleteListener(this);
mediaPlayer.setOnInfoListener(this);
mediaPlayer.reset();
// Register headset receiver
registerReceiver(headsetReceiver, new IntentFilter(
Intent.ACTION_HEADSET_PLUG));
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// get songs and position
songs = (ArrayList<Songs>) intent.getSerializableExtra("songs");
position = intent.getIntExtra("position", -1);
try {
mediaPlayer.setDataSource(songs.get(position).getLink());
} catch (IllegalArgumentException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (SecurityException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IllegalStateException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// ---Set up receiver for seekbar change ---
registerReceiver(broadcastReceiver, new IntentFilter(
Player.BROADCAST_SEEKBAR));
// Manage incoming phone calls during playback. Pause mp on incoming,
// resume on hangup.
// -----------------------------------------------------------------------------------
// Get the telephony manager
Log.v(TAG, "Starting telephony");
telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
Log.v(TAG, "Starting listener");
phoneStateListener = new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
// String stateString = "N/A";
Log.v(TAG, "Starting CallStateChange");
switch (state) {
case TelephonyManager.CALL_STATE_OFFHOOK:
case TelephonyManager.CALL_STATE_RINGING:
if (mediaPlayer != null) {
pauseMedia();
isPausedInCall = true;
}
break;
case TelephonyManager.CALL_STATE_IDLE:
// Phone idle. Start playing.
if (mediaPlayer != null) {
if (isPausedInCall) {
isPausedInCall = false;
playMedia();
}
}
break;
}
}
};
// Register the listener with the telephony manager
telephonyManager.listen(phoneStateListener,
PhoneStateListener.LISTEN_CALL_STATE);
// Insert notification start
initNotification();
mediaPlayer.reset();
// Set up the MediaPlayer data source using the strAudioLink value
if (!mediaPlayer.isPlaying()) {
try {
// Send message to Activity to display progress dialogue
sendBufferingBroadcast();
mediaPlayer.setDataSource(songs.get(position).getLink());
;
// Prepare mediaplayer
mediaPlayer.prepare();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
}
}
// --- Set up seekbar handler ---
setupHandler();
return START_STICKY;
}
// ---Send seekbar info to activity----
private void setupHandler() {
handler.removeCallbacks(sendUpdatesToUI);
handler.postDelayed(sendUpdatesToUI, 1000); // 1 second
}
private Runnable sendUpdatesToUI = new Runnable() {
public void run() {
// // Log.d(TAG, "entered sendUpdatesToUI");
LogMediaPosition();
handler.postDelayed(this, 1000); // 2 seconds
}
};
private void LogMediaPosition() {
// // Log.d(TAG, "entered LogMediaPosition");
if (mediaPlayer.isPlaying()) {
mediaPosition = mediaPlayer.getCurrentPosition();
// if (mediaPosition < 1) {
// Toast.makeText(this, "Buffering...", Toast.LENGTH_SHORT).show();
// }
mediaMax = mediaPlayer.getDuration();
// seekIntent.putExtra("time", new Date().toLocaleString());
seekIntent.putExtra("counter", String.valueOf(mediaPosition));
seekIntent.putExtra("mediamax", String.valueOf(mediaMax));
seekIntent.putExtra("song_ended", String.valueOf(songEnded));
sendBroadcast(seekIntent);
}
}
// --Receive seekbar position if it has been changed by the user in the
// activity
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateSeekPos(intent);
}
};
// Update seek position from Activity
public void updateSeekPos(Intent intent) {
int seekPos = intent.getIntExtra("seekpos", 0);
if (mediaPlayer.isPlaying()) {
handler.removeCallbacks(sendUpdatesToUI);
mediaPlayer.seekTo(seekPos);
setupHandler();
}
}
// ---End of seekbar code
// If headset gets unplugged, stop music and service.
private BroadcastReceiver headsetReceiver = new BroadcastReceiver() {
private boolean headsetConnected = false;
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
// Log.v(TAG, "ACTION_HEADSET_PLUG Intent received");
if (intent.hasExtra("state")) {
if (headsetConnected && intent.getIntExtra("state", 0) == 0) {
headsetConnected = false;
headsetSwitch = 0;
// Log.v(TAG, "State = Headset disconnected");
// headsetDisconnected();
} else if (!headsetConnected
&& intent.getIntExtra("state", 0) == 1) {
headsetConnected = true;
headsetSwitch = 1;
// Log.v(TAG, "State = Headset connected");
}
}
switch (headsetSwitch) {
case (0):
headsetDisconnected();
break;
case (1):
break;
}
}
};
private void headsetDisconnected() {
stopMedia();
stopSelf();
}
// --- onDestroy, stop media player and release. Also stop
// phoneStateListener, notification, receivers...---
#Override
public void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
}
if (phoneStateListener != null) {
telephonyManager.listen(phoneStateListener,
PhoneStateListener.LISTEN_NONE);
}
// Cancel the notification
cancelNotification();
// Unregister headsetReceiver
unregisterReceiver(headsetReceiver);
// Unregister seekbar receiver
unregisterReceiver(broadcastReceiver);
// Stop the seekbar handler from sending updates to UI
handler.removeCallbacks(sendUpdatesToUI);
// Service ends, need to tell activity to display "Play" button
resetButtonPlayStopBroadcast();
}
// Send a message to Activity that audio is being prepared and buffering
// started.
private void sendBufferingBroadcast() {
// Log.v(TAG, "BufferStartedSent");
bufferIntent.putExtra("buffering", "1");
sendBroadcast(bufferIntent);
}
// Send a message to Activity that audio is prepared and ready to start
// playing.
private void sendBufferCompleteBroadcast() {
// Log.v(TAG, "BufferCompleteSent");
bufferIntent.putExtra("buffering", "0");
sendBroadcast(bufferIntent);
}
// Send a message to Activity to reset the play button.
private void resetButtonPlayStopBroadcast() {
// Log.v(TAG, "BufferCompleteSent");
bufferIntent.putExtra("buffering", "2");
sendBroadcast(bufferIntent);
}
#Override
public void onBufferingUpdate(MediaPlayer arg0, int arg1) {
// TODO Auto-generated method stub
}
#Override
public boolean onInfo(MediaPlayer arg0, int arg1, int arg2) {
// TODO Auto-generated method stub
return false;
}
#Override
public void onSeekComplete(MediaPlayer mp) {
if (!mediaPlayer.isPlaying()) {
playMedia();
Toast.makeText(this, "SeekComplete", Toast.LENGTH_SHORT).show();
}
}
// ---Error processing ---
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
switch (what) {
case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
Toast.makeText(this,
"MEDIA ERROR NOT VALID FOR PROGRESSIVE PLAYBACK " + extra,
Toast.LENGTH_SHORT).show();
break;
case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
Toast.makeText(this, "MEDIA ERROR SERVER DIED " + extra,
Toast.LENGTH_SHORT).show();
break;
case MediaPlayer.MEDIA_ERROR_UNKNOWN:
Toast.makeText(this, "MEDIA ERROR UNKNOWN " + extra,
Toast.LENGTH_SHORT).show();
break;
}
return false;
}
#Override
public void onPrepared(MediaPlayer arg0) {
// Send a message to activity to end progress dialogue
sendBufferCompleteBroadcast();
playMedia();
}
#Override
public void onCompletion(MediaPlayer mp) {
// When song ends, need to tell activity to display "Play" button
position += 1;
stopMedia();
playMedia();
// stopSelf();
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
public void playMedia() {
if (!mediaPlayer.isPlaying()) {
try {
//line 413
mediaPlayer.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// Add for Telephony Manager
public void pauseMedia() {
// Log.v(TAG, "Pause Media");
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
public void stopMedia() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
}
// Create Notification
private void initNotification() {
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
int icon = R.drawable.ic_launcher;
CharSequence tickerText = "Tutorial: Music In Service";
long when = System.currentTimeMillis();
Notification notification = new Notification(icon, tickerText, when);
notification.flags = Notification.FLAG_ONGOING_EVENT;
Context context = getApplicationContext();
CharSequence contentTitle = "Music In Service App Tutorial";
CharSequence contentText = "Listen To Music While Performing Other Tasks";
Intent notificationIntent = new Intent(this, Player.class);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0,
notificationIntent, 0);
notification.setLatestEventInfo(context, contentTitle, contentText,
contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, notification);
}
// Cancel Notification
private void cancelNotification() {
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
mNotificationManager.cancel(NOTIFICATION_ID);
}
}
Can anyone tell me what I'm doing wrong?
First, that's not an NPE (null pointer exception).
Second, you are calling your playMedia method entirely too often. Considering that it calls MediaPlayer.prepare, it doesn't make sense in several of the places I see it being called. In particular, you are calling it in the onPrepared callback. The MediaPlayer's state machine is giving you an IllegalStateException because you can't call prepare from the prepared state. You should also not call prepare from the onCompletion callback. The MediaPlayer has a strict state machine and you should probably pay more attention to it.
In my app, I am using media player in service for playing a music file. I have used TelephonyManager in order to check for incoming and outgoing calls and playing and pausing music accordingly.
For incoming and outgoing calls, the app works fine and music pauses whenever a call takes place and resumes after the call disconnects. But when I try to pause manually after a call disconnects, it doesn't pause.
Below is my code:
public class ChalisaService extends Service
{
static MediaPlayer mediaPlayer;
static int playerFlag = 0;
TelephonyManager tm;
ActivityManager actManager;
Context mContext = getApplicationContext();
/**
* 0 for stop
* 1 for play
* 2 for pause*/
#Override
public IBinder onBind(Intent intent)
{
return null;
}//onBind
#Override
public void onCreate()
{
super.onCreate();
mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.chalisa);
mediaPlayer.setVolume(100, 100);
tm = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
tm.listen(mPhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
}//onCreate
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
if(mediaPlayer.isPlaying())
{
mediaPlayer.pause();
/*HanuAlarm.txtPlay.setText("Play");
HanuAlarm.btn_Play.setBackgroundResource(R.drawable.btnplay);*/
playerFlag = 2;
}//if
else
{
mediaPlayer.start();
/*HanuAlarm.txtPlay.setText("Pause");
HanuAlarm.btn_Play.setBackgroundResource(R.drawable.btnpause);*/
playerFlag = 1;
}//else
startForeground(0, null);
return playerFlag;
}//onStartCommand
#Override
public void onDestroy()
{
mediaPlayer.stop();
mediaPlayer.release();
playerFlag = 0;
}//onDestroy
private PhoneStateListener mPhoneListener = new PhoneStateListener() {
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
Intent i = new Intent("com.android.music.musicservicecommand");
i.putExtra("command", "pause");
mContext.sendBroadcast(i);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Intent in = new Intent("com.android.music.musicservicecommand");
in.putExtra("command", "pause");
mContext.sendBroadcast(in);
break;
case TelephonyManager.CALL_STATE_IDLE:
if(!mediaPlayer.isPlaying())
{
mediaPlayer.start();
playerFlag = 1;
}//if
else
{
Intent in1 = new Intent("com.android.music.musicservicecommand");
in1.putExtra("command", "pause");
mContext.sendBroadcast(in1);
}//else
tm.listen(mPhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
default:
Log.d("Chalisa Service", "Unknown phone state=" + state);
}
}
};
}//ChalisaService
Button code on which I am playing or pausing media player:
btn_Play.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
if(ChalisaService.playerFlag == 0 || ChalisaService.playerFlag == 2)
{
startService(in);
ChalisaService.playerFlag = 1;
Log.i("HanuAlarm play button if", ""+chalisaPlaying);
txtPlay.setText("Pause");
txtPlay.setTextColor(getResources().getColor(R.color.redwine));
btn_Play.setBackgroundResource(R.drawable.btnpause);
}//if
else if(ChalisaService.playerFlag == 1)
{
ChalisaService.mediaPlayer.pause();
ChalisaService.playerFlag = 2;
Log.i("HanuAlarm play button else", ""+chalisaPlaying);
txtPlay.setText("Play");
txtPlay.setTextColor(getResources().getColor(R.color.white));
btn_Play.setBackgroundResource(R.drawable.btnplay_a);
}//else if
}//onClick
});
I have solved my problem. Below, I am posting code for my music service.
public class ChalisaService extends Service implements OnCompletionListener
{
static MediaPlayer mediaPlayer;
static int playerFlag = 0;
TelephonyManager tm;
ActivityManager actManager;
/**
* 0 for stop/pause
* 1 for play*/
#Override
public IBinder onBind(Intent intent)
{
return null;
}//onBind
#Override
public void onCreate()
{
super.onCreate();
mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.chalisa);
mediaPlayer.setVolume(100, 100);
mediaPlayer.setOnCompletionListener(this);
tm = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
tm.listen(mPhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
}//onCreate
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
if(mediaPlayer.isPlaying())
{
mediaPlayer.pause();
/*HanuAlarm.txtPlay.setText("Play");
HanuAlarm.btn_Play.setBackgroundResource(R.drawable.btnplay);*/
playerFlag = 0;
}//if
else
{
mediaPlayer.start();
/*HanuAlarm.txtPlay.setText("Pause");
HanuAlarm.btn_Play.setBackgroundResource(R.drawable.btnpause);*/
playerFlag = 1;
}//else
startForeground(0, null);
return playerFlag;
}//onStartCommand
#Override
public void onDestroy()
{
super.onDestroy();
/*//mediaPlayer.stop();
//mediaPlayer.release();
playerFlag = 0;
Log.v("Chalisa service", "on destroy called");*/
}//onDestroy
private PhoneStateListener mPhoneListener = new PhoneStateListener() {
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
if(mediaPlayer.isPlaying())
{
mediaPlayer.pause();
playerFlag = 0;
}//if
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
if(mediaPlayer.isPlaying())
{
mediaPlayer.pause();
playerFlag = 0;
}//if
break;
/**
* Nitish
* 26 Sep 2012, Wed
* 11:50 AM*/
case TelephonyManager.CALL_STATE_IDLE:
if(!mediaPlayer.isPlaying())
{
mediaPlayer.start();
playerFlag = 1;
}//if
default:
Log.d("Chalisa Service", "Unknown phone state=" + state);
}
}
};
public void onCompletion(MediaPlayer mp)
{
mp.stop();
mp.release();
playerFlag = 0;
stopSelf();
updateUI();
Log.v("Chalisa Service media player", "on completion listener called");
}
private void updateUI()
{
Intent in = new Intent("com.dzo.HanumanChalisaWithAudioAndAlarm.UPDATE_UI");
in.putExtra("Player_FLAG_VALUE", playerFlag);
getApplicationContext().sendBroadcast(in);
}
}//ChalisaService
Try to force it pausing using:
Intent i = new Intent("com.android.music.musicservicecommand");
i.putExtra("command", "pause");
mContext.sendBroadcast(i);