Cordova 媒体插件 - 停止流式传输不起作用 - release() 冻结设备
Cordova media plugin - stop streaming not working - release() freezes the device
我在 Android 应用程序中将 cordova 6.4.0
和 cordova-plugin-media
用于流式广播电台。不幸的是,在某些情况下,应用程序不再正确响应。
假设用户想要流式传输广播电台,但在加载流时,他想中止它(例如,因为流已关闭,或加载时间很长)。
在这种情况下我无法取消进程!
media = new Media("http://direct.franceinfo.fr/live/franceinfo-midfi.mp3?ID=f9fbk29m84", mediaPlayerSuccess, mediaPlayerFail, mediaPlayerStatus);
media.play();
现在我想取消缓冲流的过程,但我不能。功能:
media.pause();
media.stop();
在 ADB 日志中抛出错误消息并调用 mediaPlayer-onError 回调。
D/AudioPlayer( 3362): AudioPlayer Error: pausePlaying() called during invalid state: 1
...
D/AudioPlayer( 3362): AudioPlayer Error: stopPlaying() called during invalid state: 1
media.release()
命令停止流的加载!然而,只是释放流而不停止它,会导致其他相当大的问题:
大多数情况下,如果您在媒体对象上调用 media.release()
,系统反应非常缓慢并挂起几秒钟。但如果您经常这样做,系统 会完全死机 。这意味着它不再接受远程控制命令。
Adb 日志仍在工作,但在这种情况下没有显示任何错误。只有电源按钮仍在工作(它锁定和解锁屏幕)。从这种搞砸状态中恢复的唯一方法是重新启动设备。
如果媒体流尚未播放,我该如何取消它?这是插件中的错误吗?
附件是我用来处理媒体流逻辑的代码片段。如上所述......它基本上可以工作,但如果你多次调用它,它会减慢甚至冻结设备。
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();
}
我发现,这不是 cordova 问题,而是一个 8 岁 (!) android-bug,从未修复。看这里:
https://code.google.com/p/android/issues/detail?id=959
MediaPlayer "crash" (deadlocks the calling thread) when resetting or releasing an unused MediaPlayer
基本上问题是:如果您尝试“释放”一个尚未播放的媒体对象,它将使调用线程死锁,这会导致我在问题中提到的冻结。不幸的是,他们从未修复过这个错误,只是将其标记为 "obsolete"。在 Android 5.1.1。该错误显然仍然存在。也许他们在以后的版本中修复了它。
我已经为这个问题做了一个相当丑陋的解决方法,但它正在工作。基本上我所做的是:
我们将每个媒体对象保存在一个 javaScript 对象中。如果用户在播放时停止它,我们可以停止并删除该对象。但是如果它不在播放,我们将这个媒体对象留在这个 javaScript-object media_objects = {};
我们还将当前 active_media
流保存在一个变量中。
如果 cordova 调用 mediaPlayerStatusChange
-回调,我们循环遍历 media_objects
并检查 "pending"-对象之一的状态现在是否已更改为 "running" . - Cordova 只是调用 media-status-change-callback 而没有任何指示什么媒体对象刚刚改变了状态。这很不幸,所以我们必须检查 pending-"obsolete" 对象之一现在是否开始播放。如果是这样,我们可以停止并释放它。 (如果对象确实在播放,停止和释放会像预期的那样工作——只有当它不在播放时,才会导致崩溃)
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];
}
}
}
这个解决方案对我有用,但是我仍然对在 cordova 中处理多个媒体流的更好、更干净的方法感兴趣。
我在 Android 应用程序中将 cordova 6.4.0
和 cordova-plugin-media
用于流式广播电台。不幸的是,在某些情况下,应用程序不再正确响应。
假设用户想要流式传输广播电台,但在加载流时,他想中止它(例如,因为流已关闭,或加载时间很长)。
在这种情况下我无法取消进程!
media = new Media("http://direct.franceinfo.fr/live/franceinfo-midfi.mp3?ID=f9fbk29m84", mediaPlayerSuccess, mediaPlayerFail, mediaPlayerStatus);
media.play();
现在我想取消缓冲流的过程,但我不能。功能:
media.pause();
media.stop();
在 ADB 日志中抛出错误消息并调用 mediaPlayer-onError 回调。
D/AudioPlayer( 3362): AudioPlayer Error: pausePlaying() called during invalid state: 1
...
D/AudioPlayer( 3362): AudioPlayer Error: stopPlaying() called during invalid state: 1
media.release()
命令停止流的加载!然而,只是释放流而不停止它,会导致其他相当大的问题:
大多数情况下,如果您在媒体对象上调用 media.release()
,系统反应非常缓慢并挂起几秒钟。但如果您经常这样做,系统 会完全死机 。这意味着它不再接受远程控制命令。
Adb 日志仍在工作,但在这种情况下没有显示任何错误。只有电源按钮仍在工作(它锁定和解锁屏幕)。从这种搞砸状态中恢复的唯一方法是重新启动设备。
如果媒体流尚未播放,我该如何取消它?这是插件中的错误吗?
附件是我用来处理媒体流逻辑的代码片段。如上所述......它基本上可以工作,但如果你多次调用它,它会减慢甚至冻结设备。
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();
}
我发现,这不是 cordova 问题,而是一个 8 岁 (!) android-bug,从未修复。看这里:
https://code.google.com/p/android/issues/detail?id=959
MediaPlayer "crash" (deadlocks the calling thread) when resetting or releasing an unused MediaPlayer
基本上问题是:如果您尝试“释放”一个尚未播放的媒体对象,它将使调用线程死锁,这会导致我在问题中提到的冻结。不幸的是,他们从未修复过这个错误,只是将其标记为 "obsolete"。在 Android 5.1.1。该错误显然仍然存在。也许他们在以后的版本中修复了它。
我已经为这个问题做了一个相当丑陋的解决方法,但它正在工作。基本上我所做的是:
我们将每个媒体对象保存在一个 javaScript 对象中。如果用户在播放时停止它,我们可以停止并删除该对象。但是如果它不在播放,我们将这个媒体对象留在这个 javaScript-object media_objects = {};
我们还将当前 active_media
流保存在一个变量中。
如果 cordova 调用 mediaPlayerStatusChange
-回调,我们循环遍历 media_objects
并检查 "pending"-对象之一的状态现在是否已更改为 "running" . - Cordova 只是调用 media-status-change-callback 而没有任何指示什么媒体对象刚刚改变了状态。这很不幸,所以我们必须检查 pending-"obsolete" 对象之一现在是否开始播放。如果是这样,我们可以停止并释放它。 (如果对象确实在播放,停止和释放会像预期的那样工作——只有当它不在播放时,才会导致崩溃)
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];
}
}
}
这个解决方案对我有用,但是我仍然对在 cordova 中处理多个媒体流的更好、更干净的方法感兴趣。