Cordoba media plugin - stop streaming does not work - release () freezes the device

I am using cordova 6.4.0 with cordova-plugin-media to stream radio stations in an android app. Unfortunately, there is a case where the application no longer responds.

Suppose that the user wants to transmit the radio station, but while the stream is loading, he wants to interrupt it (for example, because the stream is disconnected or takes a very long time).

In this case, I can not cancel the process!

 media = new Media("http://direct.franceinfo.fr/live/franceinfo-midfi.mp3?ID=f9fbk29m84", mediaPlayerSuccess, mediaPlayerFail, mediaPlayerStatus); media.play(); 

Now I want to cancel the flow buffering process, but I cannot. Functions:

 media.pause(); media.stop(); 

throw error messages into the ADB log and call the mediaPlayer-onError callback.

 D/AudioPlayer( 3362): AudioPlayer Error: pausePlaying() called during invalid state: 1 ... D/AudioPlayer( 3362): AudioPlayer Error: stopPlaying() called during invalid state: 1 

The media.release() command stops loading a stream! However, only freeing the thread without stopping it causes other, rather large problems:

In most cases, the system responds very slowly and hangs for a few seconds if you call media.release() on a media object. But if you do this often, the system ends up hanging . This means that he no longer uses remote control commands. The adb log is still working, but in this case no errors are displayed. Only the POWER button works (it locks and unlocks the screen). The only way to restore this state is to reboot the device.

How can I cancel a media stream if it is not already playing? Is this a bug in the plugin?

The attached code snippet that I use to process media streaming logic. As described above ... it basically works, but it slows down or even freezes the device if you call it several times.

 function radioControl(action, media_src){ //media_src is a webradio-streamurl. if(action == 'play') { // Initial Play if(media === null){ mediaCreateObject(media_src); } // If we get PLAY but on antoher station else if(media.src != media_src){ mediaReleaseRessources(); mediaCreateObject(media_src); } //interrupt_timer = false; if(media === null){ mediaCreateObject(media_src); } media.play(); } else if (action === 'pause') { //If we get "pause", but it didn't even start yet if(media._duration == -1){ mediaReleaseRessources(); } else{ media.pause(); } } } function mediaCreateObject(media_src){ media = new Media(media_src, mediaPlayerSuccess, mediaPlayerFail, mediaPlayerStatus); } function mediaReleaseRessources(){ media.release(); } 
+6
source share
1 answer

I found out that this is not a Cordoba problem, but an 8-year-old (!) Android bug that has never been fixed. See here:

https://code.google.com/p/android/issues/detail?id=959

MediaPlayer crashes (blocks the calling thread) when resetting or releasing unused MediaPlayer

Basically, the problem is this: if you try to “ free ” a media object that does not play (yet), it will close the calling stream, which causes the freeze that I mentioned in the question. Unfortunately, they never corrected this error, but simply marked it as "obsolete." In Android 5.1.1. the error seems to still exist. Perhaps they fixed it in later versions.


I made a rather ugly workaround for this problem, but it works. Basically what I did: We save each media object in a javaScript object. If the user stops him while he is playing, we can just stop and delete the object. But if it does not play, we leave this media object in this javaScript object media_objects = {}; We also save the current active_media stream in a variable.

If cordova calls mediaPlayerStatusChange -callback, we scroll through media_objects and check if the status of one of the "waiting" objects has changed to "running". - Cordoba justs calls the status-media change callback without any charge about which media object exactly changed state. This is unfortunate, so we need to check whether one of the waiting - "obsolete" objects began to play. If so, we can stop and free him. (If the object is actually playing, stopping and vacationing work as expected - only if it is not playing, it will crash)

 function mediaPlayerStatusChange(status){ mediaReleaseRessources(); // handle status change.... // ...... } function mediaReleaseRessources(){ for(var key in media_objects) { // We can only stop-and release an object, if it is playing // If an object started playing, the "_duration"-value is != -1 if(key !== active_media && media_objects[key]._duration != -1) { media_objects[key].stop(); media_objects[key].release(); delete media_objects[key]; } } } 

This solution works for me, but I'm still interested in a better and cleaner way to handle multiple media streams in a cord.

+3
source

Source: https://habr.com/ru/post/1013182/


All Articles