4

2 つのフラグメント (左右) があり、左側のフラグメントで Radiostreams のリストを取得します。これらのストリームのいずれかをクリックすると、正しいフラグメントがストリームの名前を変更し、指定された uri でストリームの再生を開始する必要があります。

2 問題:

  1. ラジオ ストリームの一部は最新ではないため、多くのラジオ ストリームが機能しなくなりました。問題は、これによりアプリが強制終了することです! エラー処理を行いましたが、そのようなストリームを呼び出した後、次のようになります。

03-20 14:23:28.192: A/libc(1021): 0x00000000 の致命的なシグナル 11 (SIGSEGV) (コード = 1)

03-20 14:23:28.192: W/AudioSystem(1021): AudioFlinger サーバーが停止しました!

03-20 14:23:28.192: W/IMediaDeathNotifier (1021): メディア サーバーが停止しました

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

03-20 14:23:28.192: I/ServiceManager(1021): サービス media.audio_flinger を待機しています...

03-20 14:23:28.752: I/dalvikvm(1021): threadid=3: シグナル 3 に反応しています

03-20 14:23:28.782: I/dalvikvm(1021): スタック トレースを「/data/anr/traces.txt」に書き込みました

03-20 14:23:29.192: I/ServiceManager(1021): サービス media.audio_flinger を待機しています...

どうしてか分かりません。エラー処理を行う他の方法はありますか? または、mediaPlayer.setDataSource(uri) を呼び出す前にすべてのストリームをチェックして、欠陥のある uris の準備を避ける方法はありますか? (最後に私のコードを参照してください)

  1. 左の ListFragment をリモコンで操作しています。あるチャネルから別のチャネルに非常に速く切り替えようとすると、すべてが非常に遅くなります。Mediaplayer の再インスタンス化には非常に時間がかかるようです。再インスタンス化しないと、mediaPlayer.setDataSource(..) を再度呼び出すとランタイム エラーが発生します。1 つの MediaPlayer オブジェクトで .setDataSource を 2 回呼び出す方法はありますか?

これが私のコードです: 私の MediaPlayer Wrapper クラス:

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;
        }
    }
}

これが私の TestFragment (右のフラグメント) です。注: 左の Fragment は、リスト項目がクリックされるたびに、TestFragment からメソッド「newChannel(radioChannel)」を呼び出しています。

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();
    }

}

プロの方、どちらか、または両方の質問について教えてください。

4

2 に答える 2

0

audioflinger サービス エラーに関しては、お気づきのとおり、「what == 100」または error(100,0) でマークされています。

私の謙虚な経験からオーディオフリンガーエラーを回避するためにできること:

  1. サービスへの高速呼び出しを避けます (プレーヤーの作成後に 500 ミリ秒程度の遅延を追加します)
  2. 同時にアクティブな Mediaplayer の数を制限します。

audioflinger エラーを処理するためにできること:

  1. audioflinger エラー 100 を検出し、発生したフラグを設定し、GUI を無効にします(プレーヤーのみを解放することをお勧めします。プレーヤーが既にエラー状態にあるときに停止することは安全ではなく、IllegalStateException & error(38,0) をスローするためです)
  2. サービスが戻ってきたことをテストし続ける別のスレッドを開始します(例外なしで新しいメディアプレーヤーを作成することによる可能性があります)。たとえば、5〜10秒のタイムアウトがあります
  3. サービスが戻ったら、フラグをリセットして GUI を再度有効にします

だからあなたのコードを参照してください:

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;
}

次に、ラッパーでこれを処理するメソッドを追加します。

これを解決して解決策を投稿すると、本当に感謝します。私も非常によく似た問題に直面しています。

于 2015-10-28T11:10:58.157 に答える
0

ストリームが読み込めず、準備状態でスタックしていることが多い場合は、次の場合にここでこれを試すことができますmediaWrapper.getState() == MediaPlayerStateWrapper.State.ERROR:

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

応答しないエラーAsyncTaskを回避するために、 に入れるのが最善です。または、エラーが発生した場合は、 Media Server が停止したため、新しい MediaPlayer を作成する必要があります。

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

MediaPlayerがストリームを再生している場合は、最初に停止してリセットする必要があります。

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

それは私のために働いていますが、それは最善の方法ではないと思います。準備状態で立ち往生しているときに、何をすべきかについて誰かがより良い解決策を見つけてくれることを願っています。

于 2013-03-25T14:15:53.387 に答える