Where to begin? I spent a lot of time trying to debug this, but to no avail. I ended up in deadend and am very grateful for the help.
My scenario: I'm trying to make an Android media player that will cover every song. I created 2 MediaPlayer objects (playerA and playerB), where playerA is the player who plays the โfirst songโ. The ideal scenario would be that if the user presses the next button through the MediaPlayerController OR the song ends for 10 seconds - playerA starts to disappear OUT at the same time that the player loads the song, starts playing it and the crossfade effect disappears in volume.
Although I got it to work, and I have to say that I have occasional setbacks. I would define failure as: the next song (playing through the "other" player), you will not hear anything. I checked the actual status of the player with error / silence while it demonstrates this behavior, and .isPlayer () = true and playerA.getDuration () - playerA.getCurrentPosition () calculates that MediaPlayer thinks that it actually plays - but again you Can not hear anything.
I tried a million things in different ways, but again, I canโt make it NOT accidentally break. The ways that I tried to make "repeating code" to make it disappear, and through it, through a separate thread that uses the interface handle that is in the service start method, I tried using TimerTask, and I tried using a postDelayed handler with many different delays (handler_crossfadeA.postDelayed (runnable_crossfadeA, 500);)
Some technical details: I created each playerA and playerB through a singleton that extends MediaPlayer (among millions of other things), so I only get one instance of each, my main activity is related to MusicService that plays sound, I use the Android L / 5 API I'm testing Nexus 5
So, I tracked it, minimizing my code, causing this problem (again, this is a random case - but it usually happens within 5 songs, but I got a code that can contain up to 20 songs): Given that playerA starts from the moment the application is launched, then proceeds to the next song in playerB, and then 10 seconds after the player plays, playerA stops Android AudioPlayer violated (error ioConfigChanged ()) and disconnects audio equipment (error from audio_hw_primary). In the end, I was able to reproduce this quite easily by setting the postDelayed 500 ms handler after player B started stopping playerA (removing all volume and output settings, etc.). I even tried moving my stop () and reset () code to different methods, including inside my crossfade method, inside my playSong () method in the onPrepare () method.
Summarizing:
- I can make this work fine if I remove any "sleeping" (or waiting) after I set playerB setDataSource โ start () to MediaPlaye onPrepared ().
- While this breaks this: playerA plays โ press the next song button โ playerB sets the data source โ call prepare () (prepareAsync () has the same behavior) โ onPrepared () calls start () โ sleep 500ms or longer โ stop ( ) and reset () (or just reset () player A. So again, resetting playerA AFTER playerB is already playing, which violates this. I know that my situation seems a little strange, but I really feel Android should not have problems with this . https://stackoverflow.com/questions/24603752/android-mediaplayer-crossfade applies, but by no means has the same issue.
Although I have a ton of code that would not fit in this post, after it was removed for troubleshooting, here is what I usually have (apologize in advance if I have something missing):
Part of the service start method:
handler_crossfadeA = new Handler(); guiHandler= new Handler(Looper.getMainLooper());
init () method called when the service is started for each player:
playerA.setAudioSessionId(11); playerA.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK); playerA.setAudioStreamType(AudioManager.STREAM_MUSIC); playerA.setOnPreparedListener(this); playerA.setOnCompletionListener(this); playerA.setOnErrorListener(this);
Part of the playSong () method
try{ playerA.setDataSource(getApplicationContext(), trackUri); } catch(Exception e){ } try{ playerA.prepare(); } catch (IllegalStateException e) { e.printStackTrace();} catch (IOException e) { }
Part of the onPrepared () method:
playerA.start(); //or call playerB.start if its not the next player call crossfade method
Part of the crossfade method, different options for each player:
handler_crossfadeA_iteration=0; runnable_crossfadeA = new Runnable(){ @Override public void run() { playerA.stop(); playerA.reset(); } }; handler_crossfadeA.postDelayed(runnable_crossfadeA,500); //500ms isnt ideal but i got it to still break this way
The most important error, which, it seems to me, causes the following:
- AudioSystem - ioConfigChanged () closing an unknown output!
- I searched for this error in Android C ++ code but did not find any helpful hints
The following related errors:
- audio_hw_primary - out_set_parameters: enter: usecae (3: compression offload playback) kvpairs: exiting = 1
- offload_visualizer - stream output
- audio_hw_primary - disable_audio_route: reset and update the mixer path: compress-offload-play
- audio_hw_primary - offload_thread_loop: compression descriptor is null
At a minimum, I send messages, so I hope to share my experience with others and get all this information in one place.
Full screen shot of errors: 