EasyCameraPro在直播过程中不发送START_STREAM_ACK响应的bug解决

来源:互联网 发布:linux修改网卡配置 编辑:程序博客网 时间:2024/05/22 15:58

EasyCameraPro在直播过程中不发送START_STREAM_ACK响应的bug解决

EasyCameraPro是一款按需直播的RTMP协议流媒体推送APP.EasyCameraPro在启动后,登录到EasyDSS服务器,在收到视频播放请求后,启动推送,并由服务器转发给播放端进行播放.当播放端停止播放时,服务器会给EasyCameraPro发送停止视频的命令,这时候,EasyCameraPro会停止推送.

主要有如下几种场景:

  • 首次请求推送的过程:
Created with Raphaël 2.1.0播放器播放器服务器服务器EasyCameraProEasyCameraPro1 请求播放2 请开始推送3 推送4 转发
  • 已经开始推送,第二个播放器再请求时:
Created with Raphaël 2.1.0EasyCameraProEasyCameraPro服务器服务器播放器播放器推送中1 请求播放2 转发
  • 最后一个播放器断开的情况

    Created with Raphaël 2.1.0播放器播放器服务器服务器EasyCameraProEasyCameraPro1 断开没有客户端链接了2 请断开推送3 推送断开

在我们测试的过程中发现,有时候服务器向EasyCameraPro请求推送时,EasyCameraPro会出现不应答的情况.这会导致播放端一直在等待中.而有时候却又是正常的!

看看代码是怎么回事?

@Subscribepublic void onPushOK(final PushOK ok) {  AsyncTask.execute(new Runnable() {    @Override    public void run() {      JSONObject body = ok.startStreamingReqBody;      Object channel = body.opt("Channel");      ...        respStr = buildOutStreamContent(respStr);      String info = String.format("Send MSG_SD_PUSH_STREAM_ACK RTMP [%s:%d]", body.optString("Server_IP"), body.optInt("Server_PORT"));      final String finalRespStr = respStr;      try {        synchronized (mOS) {          mOS.write(finalRespStr);          mOS.flush();        }      } catch (Exception ex) {        ex.fillInStackTrace();      }    }  });}

通过Bus收到PushOK请求后,会向服务器发送MSG_SD_PUSH_STREAM_ACK响应,由于Bus事件是在主线程接收到,所以这里我们需使用AsyncTask进行异步发送.

有经验的程序员马上就可以看出问题所在,即AsyncTask.execute方法,会将Runnable默认执行在内置的SerialExecutor中:

    private static class SerialExecutor implements Executor {        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();        Runnable mActive;        public synchronized void execute(final Runnable r) {            mTasks.offer(new Runnable() {                public void run() {                    try {                        r.run();                    } finally {                        scheduleNext();                    }                }            });            if (mActive == null) {                scheduleNext();            }        }        protected synchronized void scheduleNext() {            if ((mActive = mTasks.poll()) != null) {                THREAD_POOL_EXECUTOR.execute(mActive);            }        }    }

这个Executor,是按照顺序执行的.即所有的Runnable会排序依次执行,每次只能执行一个.

所以,MSG_SD_PUSH_STREAM_ACK没有发送出去的原因肯定是Executor中已有任务在排队了,我们这个任务没能及时执行所导致.

于是我们将AsyncTask.execute改成AsyncTask.THREAD_POOL_EXECUTOR.execute,使得我们的任务执行在线程池中,再试下,问题就解决了.

于EasyRTMP推流SDK

EasyRTMP是一套调用简单、功能完善、运行高效稳定的RTMP功能组件,经过多年实战和线上运行打造,支持RTMP推送断线重连、环形缓冲、智能丢帧、网络事件回调,支持Windows、Linux、arm(hisiv100/hisiv200/hisiv300/hisiv400/etc..)、Android、iOS平台,支持市面上绝大部分的RTMP流媒体服务器,包括Red5、Ngnix_rtmp、crtmpserver等主流RTMP服务器,能够完美应用于各种行业的直播需求,手机直播、桌面直播、摄像机直播、课堂直播等等方面!

点击链接加入群【EasyRTMP-RTMP直播推送】:587254841

阅读全文
0 0