Android MediaPlayer AudioStream AudioFlinger server died!, Fatal signal 11

4

I have two fragments (left and right) and getting in the left fragment a list of Radiostreams. By clicking on one of these streams, the right fragment should change the Name of the Stream and start playing the stream with the given uri.

2 Problems:

  1. Some of the radio streams aren't up to date, so a lot of them aren't working anymore. The problem is, this causes my app to do a forceclose! I did error handling, but after calling such a stream I get:

03-20 14:23:28.192: A/libc(1021): Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1)

03-20 14:23:28.192: W/AudioSystem(1021): AudioFlinger server died!

03-20 14:23:28.192: W/IMediaDeathNotifier(1021): media server died

03-20 14:23:28.192: E/MediaPlayer(1021): error (100, 0)

03-20 14:23:28.192: I/ServiceManager(1021): Waiting for service media.audio_flinger...

03-20 14:23:28.752: I/dalvikvm(1021): threadid=3: reacting to signal 3

03-20 14:23:28.782: I/dalvikvm(1021): Wrote stack traces to '/data/anr/traces.txt'

03-20 14:23:29.192: I/ServiceManager(1021): Waiting for service media.audio_flinger...

I don't know why. Is there any other way to do error handling? Or is there a way to check all the streams before calling mediaPlayer.setDataSource(uri) to avoid preparing defekt uris? (see my code at the end)

  1. I'm controlling the left ListFragment with a remote control. When I try to switch very fast from one channel to the other everything is very laggy. It seems that the reinstanciation of the Mediaplayer take very long. When I don't reinstanciate I get an runtimeerror when I call mediaPlayer.setDataSource(..) again. Is there a way to call .setDataSource two times on one MediaPlayer Object?

Here is my code: My MediaPlayer Wrapper class:

package net.smart4life.tvplay.model;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnInfoListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.util.Log;

/**
 * A wrapper class for {@link android.media.MediaPlayer}.
 * <p>
 * Encapsulates an instance of MediaPlayer, and makes a record of its internal
 * state accessible via a {@link MediaPlayerWrapper#getState()} accessor.
 */
public class MediaPlayerStateWrapper {

    private static String tag = "MediaPlayerWrapper";
    private MediaPlayer mPlayer;
    private State currentState;
    private MediaPlayerStateWrapper mWrapper;

    public MediaPlayerStateWrapper() {
        mWrapper = this;
        mPlayer = new MediaPlayer();
        currentState = State.IDLE;
        mPlayer.setOnPreparedListener(mOnPreparedListener);
        mPlayer.setOnCompletionListener(mOnCompletionListener);
        mPlayer.setOnBufferingUpdateListener(mOnBufferingUpdateListener);
        mPlayer.setOnErrorListener(mOnErrorListener);
        mPlayer.setOnInfoListener(mOnInfoListener);
    }

    /* METHOD WRAPPING FOR STATE CHANGES */
    public static enum State {
        IDLE, ERROR, INITIALIZED, PREPARING, PREPARED, STARTED, STOPPED, PLAYBACK_COMPLETE, PAUSED;
    }

    public void setDataSource(String path) {
        if (currentState == State.IDLE) {
            try {
                mPlayer.setDataSource(path);
                currentState = State.INITIALIZED;
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else
            throw new RuntimeException();
    }

    public void prepareAsync() {
        Log.d(tag, "prepareAsync()");
        if (EnumSet.of(State.INITIALIZED, State.STOPPED).contains(currentState)) {
            mPlayer.prepareAsync();
            currentState = State.PREPARING;
        } else
            throw new RuntimeException();
    }

    public boolean isPlaying() {
        Log.d(tag, "isPlaying()");
        if (currentState != State.ERROR) {
            return mPlayer.isPlaying();
        } else
            throw new RuntimeException();
    }

    public void seekTo(int msec) {
        Log.d(tag, "seekTo()");
        if (EnumSet.of(State.PREPARED, State.STARTED, State.PAUSED,
                State.PLAYBACK_COMPLETE).contains(currentState)) {
            mPlayer.seekTo(msec);
        } else
            throw new RuntimeException();
    }

    public void pause() {
        Log.d(tag, "pause()");
        if (EnumSet.of(State.STARTED, State.PAUSED).contains(currentState)) {
            mPlayer.pause();
            currentState = State.PAUSED;
        } else
            throw new RuntimeException();
    }

    public void start() {
        Log.d(tag, "start()");
        if (EnumSet.of(State.PREPARED, State.STARTED, State.PAUSED,
                State.PLAYBACK_COMPLETE).contains(currentState)) {
            mPlayer.start();
            currentState = State.STARTED;
        } else
            throw new RuntimeException();
    }

    public void stop() {
        Log.d(tag, "stop()");
        if (EnumSet.of(State.PREPARED, State.STARTED, State.STOPPED,
                State.PAUSED, State.PLAYBACK_COMPLETE).contains(currentState)) {
            mPlayer.stop();
            currentState = State.STOPPED;
        } else
            throw new RuntimeException();
    }

    public void reset() {
        Log.d(tag, "reset()");
        mPlayer.reset();
        currentState = State.IDLE;
    }

    /**
     * @return The current state of the mediaplayer state machine.
     */
    public State getState() {
        Log.d(tag, "getState()");
        return currentState;
    }

    public void release() {
        Log.d(tag, "release()");
        mPlayer.release();
    }

    /* INTERNAL LISTENERS */
    private OnPreparedListener mOnPreparedListener = new OnPreparedListener() {

        @Override
        public void onPrepared(MediaPlayer mp) {
            Log.d(tag, "on prepared");
            currentState = State.PREPARED;
            mWrapper.onPrepared(mp);
            mPlayer.start();
            currentState = State.STARTED;
        }
    };
    private OnCompletionListener mOnCompletionListener = new OnCompletionListener() {

        @Override
        public void onCompletion(MediaPlayer mp) {
            Log.d(tag, "on completion");
            currentState = State.PLAYBACK_COMPLETE;
            mWrapper.onCompletion(mp);
        }
    };
    private OnBufferingUpdateListener mOnBufferingUpdateListener = new OnBufferingUpdateListener() {

        @Override
        public void onBufferingUpdate(MediaPlayer mp, int percent) {
            Log.d(tag, "on buffering update");
            mWrapper.onBufferingUpdate(mp, percent);
        }
    };
    private OnErrorListener mOnErrorListener = new OnErrorListener() {

        @Override
        public boolean onError(MediaPlayer mp, int what, int extra) {
            Log.d(tag, "on error");
            currentState = State.ERROR;
            mWrapper.onError(mp, what, extra);
            return false;
        }
    };
    private OnInfoListener mOnInfoListener = new OnInfoListener() {

        @Override
        public boolean onInfo(MediaPlayer mp, int what, int extra) {
            Log.d(tag, "on info");
            mWrapper.onInfo(mp, what, extra);
            return false;
        }
    };

    /* EXTERNAL STUBS TO OVERRIDE */
    public void onPrepared(MediaPlayer mp) {
    }

    public void onCompletion(MediaPlayer mp) {
    }

    public void onBufferingUpdate(MediaPlayer mp, int percent) {
    }

    boolean onError(MediaPlayer mp, int what, int extra) {
        // Error Handling of type: "MEdiaPlayer error(100,0)
        mp.stop();
        mp.release();
        return false;
    }

    public boolean onInfo(MediaPlayer mp, int what, int extra) {
        return false;
    }

    /* OTHER STUFF */
    public int getCurrentPosition() {
        if (currentState != State.ERROR) {
            return mPlayer.getCurrentPosition();
        } else {
            return 0;
        }
    }

    public int getDuration() {
        // Prepared, Started, Paused, Stopped, PlaybackCompleted
        if (EnumSet.of(State.PREPARED, State.STARTED, State.PAUSED,
                State.STOPPED, State.PLAYBACK_COMPLETE).contains(currentState)) {
            return mPlayer.getDuration();
        } else {
            return 100;
        }
    }
}

Here is my TestFragment (right Fragment). Note: the left Fragment is calling the method "newChannel(radioChannel)" from TestFragment, everytime a listitem was clicked.

package net.smart4life.tvplay.fragment;

import java.io.IOException;

import net.smart4life.tvplay.R;
import net.smart4life.tvplay.model.MediaPlayerStateWrapper;
import net.smart4life.tvplay.model.RadioChannel;
import android.app.Fragment;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

public class TestFragment extends Fragment {

    private RadioChannel radioCh;
    private TextView tv_RadioCh;
    private MediaPlayerStateWrapper mediaWrapper;
    private View view;


    // firstcall
    public TestFragment(RadioChannel radioChannel) {
        this.radioCh = radioChannel;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onActivityCreated(savedInstanceState);

        setRetainInstance(true);

        tv_RadioCh = (TextView) view.findViewById(R.id.radioText);

        mediaWrapper = new MediaPlayerStateWrapper();

        newChannel(radioCh);
    }

    public void newChannel (RadioChannel radioChannel) {
        this.radioCh = radioChannel;
        Log.e("RadioChannel", radioCh.getName());
        tv_RadioCh.setText(radioCh.getName());

        if(mediaWrapper.isPlaying()) {
            mediaWrapper.stop();
            mediaWrapper.reset(); 
        } else if(mediaWrapper.getState() == MediaPlayerStateWrapper.State.PREPARING) {
            mediaWrapper.release();
            mediaWrapper = new MediaPlayerStateWrapper();
        }
        mediaWrapper.setDataSource(radioCh.getUrl().toString());    
        mediaWrapper.prepareAsync();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        view = inflater.inflate(R.layout.fragment_radio_player, container,
                false);

        return view;
    }

    @Override
    public void onDetach() {
        super.onDetach();

        mediaWrapper.release();
    }

}

Pros, could you please help me with one or both questions?

android
media-player
forceclose
servicemanager
audioflinger
asked on Stack Overflow Mar 20, 2013 by StackYouMore

2 Answers

0

If a stream can't load you're often stucked in the prepare state, you can try this here, when mediaWrapper.getState() == MediaPlayerStateWrapper.State.ERROR:

mediaWrapper.reset();
mediaWrapper.release();
System.gc();
mediaWrapper = new MediaPlayerStateWrapper();
mediaWrapper.setDataSource(radioCh.getUrl().toString());
mediaWrapper.prepareAsync();

Best to put it in an AsyncTask, to avoid Not responding error. Or when you get an Error you have to create a new MediaPlayer, because Media Server died:

if(mediaWrapper.getState() == MediaPlayerStateWrapper.State.ERROR){
    mediaWrapper = new MediaPlayerStateWrapper();
    mediaWrapper.setDataSource(radioCh.getUrl().toString());
    mediaWrapper.prepareAsync();
}

If the MediaPlayer is playing a stream you have to stop and reset it first :

mediaWrapper.stop();
mediaWrapper.reset();
mediaWrapper.setDataSource(radioCh.getUrl().toString());
mediaWrapper.prepareAsync();

It's working for me but i think it isn't the best way. Hope someone can find a better solution for what to do, when you're stucked in the prepare state.

answered on Stack Overflow Mar 25, 2013 by Duglah
0

Regarding the audioflinger service error, as you have noticed, it is marked by "what == 100" or error(100,0).

What you can do to avoid audioflinger error from my humble experience:

  1. Avoid fast calls to the service (I do add like 500 millis delay after creating the player)
  2. Limit the number of concurrent Mediaplayers active at the same time.

What you can do to handle audioflinger error:

  1. Detect the audioflinger error 100, set a flag it occurred and disable GUI (releasing the player only is recommended, as stopping it when it already is in error state is not safe and will throw IllegalStateException & error(38,0)
  2. Start another thread that keeps testing the service is back (could be by creating a new mediaplayer with no exceptions) with a timeout of let's say 5-10 seconds
  3. When the Service is back reset the flag and re-enable GUI

So referring to your code:

boolean onError(MediaPlayer mp, int what, int extra) {
    // Error Handling of type: "MEdiaPlayer error(100,0)
    mp.release();
    // here you add logic communicating the wrapper or main UI thread
    // to disable GUI and set a flag
    return false;
}

Then you add a method to handle this at the wrapper.

I would be really grateful when you work this out and post a solution. I too am facing a very similar problem.

answered on Stack Overflow Oct 28, 2015 by hannunehg

User contributions licensed under CC BY-SA 3.0