2016-12-19 8 views
2

Ich arbeite an einem Service, der ein Lied spielt, das von einem ArrayList ausgewählt wird. Das Problem kommt, wenn ich prepare() und prepareAsync() Methoden verwenden, also hier ist der Code:ANDROID: MediaPlayer zeigt Fehler (1, -19)

public class MusicService extends Service implements MediaPlayer.OnPreparedListener{ 
    private final static int DEF_VALUE = -1; 
    private Context mContext; 
    private ArrayList<Song> mSongsList; 
    private MediaPlayer mPlayer; 
    private boolean isPlaying = false; 
    private int mPosition; 

    @Nullable 
    @Override 
    public IBinder onBind(Intent intent) { 
     return null; 
    } 

    @Override 
    public void onCreate(){ 
     super.onCreate(); 
     mContext = getApplicationContext(); 
     mSongsList = new ArrayList<Song>(); 
     mPlayer = new MediaPlayer(); 
     setMusicPlayer(); 
    } 

    public void setMusicPlayer(){ 
     //Setting player properties 
     mPlayer.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK); 
     mPlayer.setAudioSessionId(AudioManager.STREAM_MUSIC); 
     mPlayer.setOnPreparedListener(this); 
    } 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     int mCommand = intent.getIntExtra("CMD", DEF_VALUE); 
     int mTrackSelected = intent.getIntExtra("TRACK_CLICKED", DEF_VALUE); 

     /** SERVICE COMMANDS 
     * 0 = SERVICE PERMISSIONS 
     * 1 = PLAY_PAUSE 
     * 2 = NEXT TRACK 
     * 3 = PREV TRACK 
     * 4 = SONG IN LIST 
     */ 

     switch (mCommand){ 
      case 0: 
       GetTracks mGetSongs = new GetTracks(); 
       mSongsList = mGetSongs.listAllSongs(mContext); 
       Log.d("test size arrayList", ""+mSongsList.size()); 
       break; 
      case 1: 
       setPlayPause(); 
       break; 
      case 2: 
       skipNextTrack(); 
       break; 
      case 3: 
       skipPrevTrack(); 
       break; 
      case 4: 
       if(mTrackSelected != DEF_VALUE){ 
        mPosition = mTrackSelected; 
        setSongToPlay(mPosition); 
       } 
       break; 
      default: 
       Log.d("error cmd", "You shouldn't be here!"); 
       break; 
     } 

     return START_STICKY; 
    } 

    private void skipPrevTrack() { 
     Log.d("method called:", "skipPrevTrack()"); 
     if(mPosition == 0){ 
      setSongToPlay(mPosition = mSongsList.size()-1); 
     } else setSongToPlay(--mPosition); 
     Log.d("test mPosition service", ""+mPosition); 
    } 

    private void skipNextTrack() { 
     Log.d("method called:", "skipNextTrack()"); 
     if(mPosition == mSongsList.size()-1){ 
      setSongToPlay(mPosition = 0); 
     } else setSongToPlay(++mPosition); 
     Log.d("test mPosition service", ""+mPosition); 
    } 


    private void setSongToPlay(int pos) { 
     Log.d("method called:", "setSongToPlay("+pos+")"); 
     startSong(mSongsList.get(pos).getSongUri()); 
    } 
    private void startSong(Uri uri){ 

     try{ 
      mPlayer.reset(); 
      mPlayer.setDataSource(mContext, uri); 
      mPlayer.prepareAsync(); 

      /** +++WORKS FINE WITH THIS CODE+++ 
      mPlayer = MediaPlayer.create(mContext, uri); 
      mPlayer.start(); 
      */ 

     } catch (Exception e){ 
      e.printStackTrace(); 
     } 
    } 

    private void setPlayPause() { 
     Log.d("method called:", "setPlayPause()"); 
    } 

    @Override 
    public void onPrepared(MediaPlayer mp) { 
     mp.start(); 
    } 
} 

LOG:

12-19 16:12:18.325 4013-4013/sebbsoft.myApp D/method called:: setSongToPlay(3) 
12-19 16:12:18.341 4013-4013/sebbsoft.myApp D/test song playing: Fiori del male ft. Sfera Ebbasta 
12-19 16:12:18.363 4013-4013/sebbsoft.myApp D/MediaPlayer: setSubtitleAnchor in MediaPlayer 
12-19 16:12:18.428 4013-4028/sebbsoft.myApp E/MediaPlayer: error (1, -19) 

Wie kann ich es lösen?

+0

veröffentlichen den vollständigen Stack-Trace –

+0

Es gibt mir nur die Zeilen, die ich in LOG – Sabatino

+0

Check letzten Teil meiner Antwort geschrieben kann es Ihnen –

Antwort

1

Endlich gelöst! Nach vielen Versuchen & Fehler !! Das ist die Linie, die es für mich verursacht:

mMediaPlayer.setAudioSessionId(AudioManager.STREAM_MUSIC); 

Die API doc für setAudioSessionId keine Alternative anzeigt oder ein Problem auf noch es verwendet, die es schwer zu debuggen gemacht. Aber ich sah setAudioStreamType unmittelbar darunter, die veraltet ist und schlägt vor, setAudioAttributes statt, w/c in API hinzugefügt wird 21.

Also änderte ich den obigen Code dazu:

if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 
     mMediaPlayer.setAudioAttributes(new AudioAttributes.Builder() 
       .setUsage(AudioAttributes.USAGE_MEDIA) 
       .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) 
       .build()); 
} else { 
     mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 
} 

Und jetzt funktioniert es!

By the way, wie Sie sehen können, überprüfte ich nur gegen Version N (API 24) und oben statt von LOLLIPOP obwohl setAudioAttributes in API 21 hinzugefügt wurde, weil ich dieses Problem nur auftreten, auf Nougat Geräten setAudioSessionId Werke bis zu Marshmallow-Geräten für mich also ... will nichts kaputt machen, das schon funktioniert.

Ich hoffe, dass jemand vorbeikommen und erklären würde, warum das passiert und was der Fehler wirklich bedeutet.

Hoffnung spart jemand Tagen Kopfschmerzen :)

EDIT: Für alle googeln um, ich änderte auch die ursprüngliche mMediaPlayer.setAudioSessionId-mMediaPlayer.setAudioStreamType, wie von Eugen Pechanec hingewiesen. Sehen Sie seinen Kommentar und antworten Sie für Details. Sie möchten auch von der Überprüfung gegen Build.VERSION_CODES.N zu Build.VERSION_CODES.LOLLIPOP damit wechseln.

+0

Ich glaube nicht, dass Sie 'setAudioSessionId' korrekt verwenden. 'setAudioAttributes' ist seit Lollipop verfügbar, aber die alte Version von' setAudioStreamType'. 'setAudioSessionId' soll mit' AudioManager.generateAudioSessionId() 'NICHT mit einem Stream-Typ verwendet werden. –

+0

Woah! Du hast recht! Ich wurde von diesen Methoden verwirrt. Danke, dass du das unterstrichen hast! :) – Mon

0

Stellen Sie sicher, dass nicht zu viele MediaPlayer Objekte gleichzeitig aktiv sind.

Implementieren Sie die OnCompletionListener und registrieren Sie sie mit Ihrer MediaPlayer Instanz. onCompletion wird aufgerufen, wenn das Ende einer Medienquelle während der Wiedergabe erreicht wird.

void onCompletion(MediaPlayer mp){ 
    //Here you stop it. 
    mp.stop(); 
    mPlayer.reset() 
    //Reset the data source path to the new file 
    mp.setDataSource(<uri>); 
    mPlayer.prepare(); // or mPlayer.prepareAsync(); 
    // start the mediaplayer after the prepare has completed. 
} 

Lassen Sie die mediaplayer Instanz, wenn Sie alle Dateien fertig spielen.


Kann sein, Ihre Zuhörer einmal nur zuhören, dann, wenn es versucht, die nächsten zu spielen, ohne vorbereitet, dann kann es .. Absturz dies versuchen zu

dieses Add ->mPlayer.setOnPreparedListener(this); in Ihrer startSong() Methode vor Ihrem prepareAsync

+0

ich nur, dass feine mein Code funktioniert auf meinem persönlichen Handy mit Android-Eibisch bemerkt habe, helfen, aber es gibt immer noch diesen Fehler auf einem Handy, das ich zum Testen (ein Galaxy S3 mit einem 7.1.1 ROM) – Sabatino

+0

verwenden kann, können Sie versuchen, n 'android: largeHeap =" true "' zu verwenden, um eine größere Heap-Größe zu verlangen und sehen Sie in Ihrem Menifest –

1

Sie verwenden setAudioSessionId falsch.

Die Audio-Session-ID ist ein systemweit eindeutige Kennung für das Audio von dieser Mediaplayer-Instanz gespielt Stream.

[...]

Wenn erstellt, eine Mediaplayer-Instanz automatisch eine eigene Audio-Session-ID erzeugt. ist es jedoch möglich, diesen Player durch Aufruf dieser Methode zu einer bereits vorhandenen Audiositzung zu zwingen. Diese Methode muss vor einer der überladenen setDataSource Methoden aufgerufen werden.

Sie erhalten eine Audio-Sitzungs-ID, indem Sie AudioManager.generateAudioSessionId() anrufen.


Was Sie wahrscheinlich suchen, wenn Sie den Stream-Typ festlegen möchten ist MediaPlayer.setAudioStreamType(int).

Neuere API für dieses seit Android 5 verfügbar ist MediaPlayer.setAudioAttributes(AudioAttibutes).

Verwandte Themen